diff --git a/.gitignore b/.gitignore
index 65f947769..3bb499198 100644
--- a/.gitignore
+++ b/.gitignore
@@ -140,6 +140,7 @@ _TeamCity*
# Visual Studio code coverage results
*.coverage
*.coveragexml
+/coveragereport/
# NCrunch
_NCrunch_*
diff --git a/Directory.Build.props b/Directory.Build.props
index 50865cda8..762d2dd09 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -23,7 +23,7 @@
embedded
true
- $(MSBuildThisFileDirectory)\strongname.snk
+ $(MSBuildThisFileDirectory)strongname.snk
Andrew Arnott
aarnott
@@ -42,9 +42,9 @@
-
+
-
+
@@ -81,7 +81,7 @@
It's also not necessary to generate these assets.
-->
- <_WpfTempProjectNuGetFilePathNoExt>$(RepoRootPath)obj\$(_TargetAssemblyProjectName)\$(_TargetAssemblyProjectName)$(MSBuildProjectExtension).nuget.g
+ <_WpfTempProjectNuGetFilePathNoExt>$(BaseIntermediateOutputPath)..\$(_TargetAssemblyProjectName)\$(_TargetAssemblyProjectName)$(MSBuildProjectExtension).nuget.g
false
false
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index dd346ab8e..2d2e4e35f 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -13,6 +13,12 @@ trigger:
- .github/
- azure-pipelines/release.yml
+parameters:
+- name: RunTests
+ displayName: Run tests
+ type: boolean
+ default: true
+
resources:
containers:
- container: xenial
@@ -37,9 +43,12 @@ stages:
- stage: Build
jobs:
- template: azure-pipelines/build.yml
+ parameters:
+ RunTests: ${{ parameters.RunTests }}
- stage: Test
displayName: Functional testing
+ condition: and(succeeded(), ${{ parameters.RunTests }})
jobs:
- job: linux
strategy:
diff --git a/azure-pipelines/Get-CodeCovTool.ps1 b/azure-pipelines/Get-CodeCovTool.ps1
new file mode 100644
index 000000000..ca580b4db
--- /dev/null
+++ b/azure-pipelines/Get-CodeCovTool.ps1
@@ -0,0 +1,86 @@
+<#
+.SYNOPSIS
+ Downloads the CodeCov.io uploader tool and returns the path to it.
+.PARAMETER AllowSkipVerify
+ Allows skipping signature verification of the downloaded tool if gpg is not installed.
+#>
+[CmdletBinding()]
+Param(
+ [switch]$AllowSkipVerify
+)
+
+if ($IsMacOS) {
+ $codeCovUrl = "https://uploader.codecov.io/latest/macos/codecov"
+ $toolName = 'codecov'
+}
+elseif ($IsLinux) {
+ $codeCovUrl = "https://uploader.codecov.io/latest/linux/codecov"
+ $toolName = 'codecov'
+}
+else {
+ $codeCovUrl = "https://uploader.codecov.io/latest/windows/codecov.exe"
+ $toolName = 'codecov.exe'
+}
+
+$shaSuffix = ".SHA256SUM"
+$sigSuffix = $shaSuffix + ".sig"
+
+Function Get-FileFromWeb([Uri]$Uri, $OutDir) {
+ $OutFile = Join-Path $OutDir $Uri.Segments[-1]
+ if (!(Test-Path $OutFile)) {
+ Write-Verbose "Downloading $Uri..."
+ if (!(Test-Path $OutDir)) { New-Item -ItemType Directory -Path $OutDir | Out-Null }
+ try {
+ (New-Object System.Net.WebClient).DownloadFile($Uri, $OutFile)
+ } finally {
+ # This try/finally causes the script to abort
+ }
+ }
+
+ $OutFile
+}
+
+$toolsPath = & "$PSScriptRoot\Get-TempToolsPath.ps1"
+$binaryToolsPath = Join-Path $toolsPath codecov
+$testingPath = Join-Path $binaryToolsPath unverified
+$finalToolPath = Join-Path $binaryToolsPath $toolName
+
+if (!(Test-Path $finalToolPath)) {
+ if (Test-Path $testingPath) {
+ Remove-Item -Recurse -Force $testingPath # ensure we download all matching files
+ }
+ $tool = Get-FileFromWeb $codeCovUrl $testingPath
+ $sha = Get-FileFromWeb "$codeCovUrl$shaSuffix" $testingPath
+ $sig = Get-FileFromWeb "$codeCovUrl$sigSuffix" $testingPath
+ $key = Get-FileFromWeb https://keybase.io/codecovsecurity/pgp_keys.asc $testingPath
+
+ if ((Get-Command gpg -ErrorAction SilentlyContinue)) {
+ Write-Host "Importing codecov key" -ForegroundColor Yellow
+ gpg --import $key
+ Write-Host "Verifying signature on codecov hash" -ForegroundColor Yellow
+ gpg --verify $sig $sha
+ } else {
+ if ($AllowSkipVerify) {
+ Write-Warning "gpg not found. Unable to verify hash signature."
+ } else {
+ throw "gpg not found. Unable to verify hash signature. Install gpg or add -AllowSkipVerify to override."
+ }
+ }
+
+ Write-Host "Verifying hash on downloaded tool" -ForegroundColor Yellow
+ $actualHash = (Get-FileHash -Path $tool -Algorithm SHA256).Hash
+ $expectedHash = (Get-Content $sha).Split()[0]
+ if ($actualHash -ne $expectedHash) {
+ # Validation failed. Delete the tool so we can't execute it.
+ #Remove-Item $codeCovPath
+ throw "codecov uploader tool failed signature validation."
+ }
+
+ Copy-Item $tool $finalToolPath
+
+ if ($IsMacOS -or $IsLinux) {
+ chmod u+x $finalToolPath
+ }
+}
+
+return $finalToolPath
diff --git a/azure-pipelines/Get-SymbolFiles.ps1 b/azure-pipelines/Get-SymbolFiles.ps1
index fccb1bb13..0ce229fc2 100644
--- a/azure-pipelines/Get-SymbolFiles.ps1
+++ b/azure-pipelines/Get-SymbolFiles.ps1
@@ -18,7 +18,7 @@ Write-Progress -Activity $ActivityName -CurrentOperation "Discovery PDB files"
$PDBs = Get-ChildItem -rec "$Path/*.pdb"
# Filter PDBs to product OR test related.
-$testregex = "unittest|tests"
+$testregex = "unittest|tests|\.test\."
Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols"
$PDBsByHash = @{}
@@ -49,8 +49,13 @@ $PDBs |% {
$BinaryImagePath = $dllPath
} elseif (Test-Path $exePath) {
$BinaryImagePath = $exePath
+ } else {
+ Write-Warning "`"$_`" found with no matching binary file."
+ $BinaryImagePath = $null
}
- Write-Output $BinaryImagePath
- Write-Output $_.FullName
+ if ($BinaryImagePath) {
+ Write-Output $BinaryImagePath
+ Write-Output $_.FullName
+ }
}
diff --git a/azure-pipelines/Merge-CodeCoverage.ps1 b/azure-pipelines/Merge-CodeCoverage.ps1
new file mode 100644
index 000000000..91ab67ab3
--- /dev/null
+++ b/azure-pipelines/Merge-CodeCoverage.ps1
@@ -0,0 +1,46 @@
+#!/usr/bin/env pwsh
+
+<#
+.SYNOPSIS
+ Merges code coverage reports.
+.PARAMETER Path
+ The path(s) to search for Cobertura code coverage reports.
+.PARAMETER Format
+ The format for the merged result. The default is Cobertura
+.PARAMETER OutputDir
+ The directory the merged result will be written to. The default is `coveragereport` in the root of this repo.
+#>
+[CmdletBinding()]
+Param(
+ [Parameter(Mandatory=$true)]
+ [string[]]$Path,
+ [ValidateSet('Badges', 'Clover', 'Cobertura', 'CsvSummary', 'Html', 'Html_Dark', 'Html_Light', 'HtmlChart', 'HtmlInline', 'HtmlInline_AzurePipelines', 'HtmlInline_AzurePipelines_Dark', 'HtmlInline_AzurePipelines_Light', 'HtmlSummary', 'JsonSummary', 'Latex', 'LatexSummary', 'lcov', 'MarkdownSummary', 'MHtml', 'PngChart', 'SonarQube', 'TeamCitySummary', 'TextSummary', 'Xml', 'XmlSummary')]
+ [string]$Format='Cobertura',
+ [string]$OutputDir=("$PSScriptRoot/../coveragereport")
+)
+
+$RepoRoot = [string](Resolve-Path $PSScriptRoot/..)
+
+if (!(Test-Path $RepoRoot/obj/reportgenerator*)) {
+ dotnet tool install --tool-path $RepoRoot/obj dotnet-reportgenerator-globaltool --version 5.1.9 --configfile $PSScriptRoot/justnugetorg.nuget.config
+}
+
+Write-Verbose "Searching $Path for *.cobertura.xml files"
+$reports = Get-ChildItem -Recurse $Path -Filter *.cobertura.xml
+
+if ($reports) {
+ $reports |% { $_.FullName } |% {
+ # In addition to replacing {reporoot}, we also normalize on one kind of slash so that the report aggregates data for a file whether data was collected on Windows or not.
+ $xml = [xml](Get-Content -Path $_)
+ $xml.coverage.packages.package.classes.class |? { $_.filename} |% {
+ $_.filename = $_.filename.Replace('{reporoot}', $RepoRoot).Replace([IO.Path]::AltDirectorySeparatorChar, [IO.Path]::DirectorySeparatorChar)
+ }
+
+ $xml.Save($_)
+ }
+
+ $Inputs = [string]::join(';', ($reports |% { Resolve-Path -relative $_.FullName }))
+ & "$RepoRoot/obj/reportgenerator" -reports:"$Inputs" -targetdir:$OutputDir -reporttypes:$Format
+} else {
+ Write-Error "No reports found to merge."
+}
diff --git a/azure-pipelines/artifacts/_all.ps1 b/azure-pipelines/artifacts/_all.ps1
index c9182a45a..033cc87c9 100644
--- a/azure-pipelines/artifacts/_all.ps1
+++ b/azure-pipelines/artifacts/_all.ps1
@@ -15,6 +15,7 @@
Executes artifact scripts even if they have already been staged.
#>
+[CmdletBinding(SupportsShouldProcess = $true)]
param (
[string]$ArtifactNameSuffix,
[switch]$Force
diff --git a/azure-pipelines/artifacts/_pipelines.ps1 b/azure-pipelines/artifacts/_pipelines.ps1
index a62d2675b..2d3338b24 100644
--- a/azure-pipelines/artifacts/_pipelines.ps1
+++ b/azure-pipelines/artifacts/_pipelines.ps1
@@ -1,6 +1,10 @@
-# This script translates all the artifacts described by _all.ps1
-# into commands that instruct Azure Pipelines to actually collect those artifacts.
+<#
+.SYNOPSIS
+ This script translates all the artifacts described by _all.ps1
+ into commands that instruct Azure Pipelines to actually collect those artifacts.
+#>
+[CmdletBinding()]
param (
[string]$ArtifactNameSuffix,
[switch]$StageOnly
diff --git a/azure-pipelines/artifacts/_stage_all.ps1 b/azure-pipelines/artifacts/_stage_all.ps1
index b7166b4eb..d81d16d46 100644
--- a/azure-pipelines/artifacts/_stage_all.ps1
+++ b/azure-pipelines/artifacts/_stage_all.ps1
@@ -1,6 +1,10 @@
-# This script links all the artifacts described by _all.ps1
-# into a staging directory, reading for uploading to a cloud build artifact store.
-# It returns a sequence of objects with Name and Path properties.
+<#
+.SYNOPSIS
+ This script links all the artifacts described by _all.ps1
+ into a staging directory, reading for uploading to a cloud build artifact store.
+ It returns a sequence of objects with Name and Path properties.
+#>
+
[CmdletBinding()]
param (
[string]$ArtifactNameSuffix
diff --git a/azure-pipelines/artifacts/coverageResults.ps1 b/azure-pipelines/artifacts/coverageResults.ps1
index 8fdb3f720..280ff9ae0 100644
--- a/azure-pipelines/artifacts/coverageResults.ps1
+++ b/azure-pipelines/artifacts/coverageResults.ps1
@@ -1,10 +1,11 @@
$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..")
+$coverageFiles = @(Get-ChildItem "$RepoRoot/test/*.cobertura.xml" -Recurse | Where {$_.FullName -notlike "*/In/*" -and $_.FullName -notlike "*\In\*" })
+
# Prepare code coverage reports for merging on another machine
if ($env:SYSTEM_DEFAULTWORKINGDIRECTORY) {
Write-Host "Substituting $env:SYSTEM_DEFAULTWORKINGDIRECTORY with `"{reporoot}`""
- $reports = Get-ChildItem "$RepoRoot/bin/coverage.*cobertura.xml" -Recurse
- $reports |% {
+ $coverageFiles |% {
$content = Get-Content -Path $_ |% { $_ -Replace [regex]::Escape($env:SYSTEM_DEFAULTWORKINGDIRECTORY), "{reporoot}" }
Set-Content -Path $_ -Value $content -Encoding UTF8
}
@@ -16,7 +17,7 @@ if (!((Test-Path $RepoRoot\bin) -and (Test-Path $RepoRoot\obj))) { return }
@{
$RepoRoot = (
- @(Get-ChildItem "$RepoRoot\bin\coverage.*cobertura.xml" -Recurse) +
+ $coverageFiles +
(Get-ChildItem "$RepoRoot\obj\*.cs" -Recurse)
);
}
diff --git a/azure-pipelines/artifacts/testResults.ps1 b/azure-pipelines/artifacts/testResults.ps1
index 2f894c97b..301a43763 100644
--- a/azure-pipelines/artifacts/testResults.ps1
+++ b/azure-pipelines/artifacts/testResults.ps1
@@ -1,16 +1,11 @@
+[CmdletBinding()]
+Param(
+)
+
$result = @{}
-if ($env:AGENT_TEMPDIRECTORY) {
- # The DotNetCoreCLI uses an alternate location to publish these files
- $guidRegex = '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$'
- $result[$env:AGENT_TEMPDIRECTORY] = (Get-ChildItem $env:AGENT_TEMPDIRECTORY -Directory |? { $_.Name -match $guidRegex } |% {
- Get-ChildItem "$($_.FullName)\dotnet*.dmp","$($_.FullName)\*_crashdump.dmp","$($_.FullName)\testhost*.dmp","$($_.FullName)\Sequence_*.xml" -Recurse
- });
-}
-else {
- $testRoot = Resolve-Path "$PSScriptRoot\..\..\test"
- $result[$testRoot] = (Get-ChildItem "$testRoot\TestResults" -Recurse -Directory | Get-ChildItem -Recurse -File)
-}
+$testRoot = Resolve-Path "$PSScriptRoot\..\..\test"
+$result[$testRoot] = (Get-ChildItem "$testRoot\TestResults" -Recurse -Directory | Get-ChildItem -Recurse -File)
$testlogsPath = "$env:BUILD_ARTIFACTSTAGINGDIRECTORY\test_logs"
if (Test-Path $testlogsPath) {
diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml
index 019cb2e30..bc31259c6 100644
--- a/azure-pipelines/build.yml
+++ b/azure-pipelines/build.yml
@@ -3,6 +3,9 @@ parameters:
type: object
default:
vmImage: windows-2022
+- name: RunTests
+ type: boolean
+ default: true
jobs:
- job: Windows
@@ -21,24 +24,26 @@ jobs:
Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile dotnet-install.ps1
& .\dotnet-install.ps1 -Architecture x86 -Channel 3.1 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose -Runtime dotnet
& .\dotnet-install.ps1 -Architecture x86 -Version 6.0.301 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose
- displayName: Install 32-bit .NET SDK and runtimes
+ displayName: โ Install 32-bit .NET SDK and runtimes
- powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud -c'
- displayName: Set build number
+ displayName: โ Set build number
- template: dotnet.yml
+ parameters:
+ RunTests: ${{ parameters.RunTests }}
- job: Linux
pool:
vmImage: Ubuntu 20.04
- variables:
- testModifier: -f net6.0
steps:
- checkout: self
clean: true
submodules: true # keep the warnings quiet about the wiki not being enlisted
- template: install-dependencies.yml
- template: dotnet.yml
+ parameters:
+ RunTests: ${{ parameters.RunTests }}
- job: WrapUp
dependsOn:
@@ -52,5 +57,6 @@ jobs:
- template: install-dependencies.yml
parameters:
initArgs: -NoRestore
- - template: publish-codecoverage.yml
+ - ${{ if parameters.RunTests }}:
+ - template: publish-codecoverage.yml
- template: publish-deployables.yml
diff --git a/azure-pipelines/dotnet-test-cloud.ps1 b/azure-pipelines/dotnet-test-cloud.ps1
index 43cdc3e00..24bf812a1 100644
--- a/azure-pipelines/dotnet-test-cloud.ps1
+++ b/azure-pipelines/dotnet-test-cloud.ps1
@@ -48,7 +48,8 @@ if ($x86) {
--no-build `
-c $Configuration `
--filter "TestCategory!=FailsInCloudTest" `
- -p:CollectCoverage=true `
+ --collect "Code Coverage;Format=cobertura" `
+ --settings "$PSScriptRoot/test.runsettings" `
--blame-hang-timeout 60s `
--blame-crash `
-bl:"$ArtifactStagingFolder/build_logs/test.binlog" `
diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml
index cf5969443..8e3415259 100644
--- a/azure-pipelines/dotnet.yml
+++ b/azure-pipelines/dotnet.yml
@@ -1,3 +1,6 @@
+parameters:
+ RunTests:
+
steps:
- script: |
@@ -6,7 +9,7 @@ steps:
displayName: Configure git commit author for testing
- script: dotnet build -t:build,pack --no-restore -c $(BuildConfiguration) /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog"
- displayName: dotnet build
+ displayName: ๐ dotnet build
- script: dotnet pack -c $(BuildConfiguration) --no-build -p:PackLKG=true /bl:"$(Build.ArtifactStagingDirectory)/build_logs/msbuild_lkg.binlog"
displayName: Build LKG package
@@ -21,10 +24,11 @@ steps:
workingDirectory: src/nerdbank-gitversioning.npm
- powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults
- displayName: dotnet test
+ displayName: ๐งช dotnet test
+ condition: and(succeeded(), ${{ parameters.RunTests }})
- powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults -X86
- displayName: dotnet test x86
+ displayName: ๐งช dotnet test x86
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
- powershell: azure-pipelines/artifacts/_pipelines.ps1 -ArtifactNameSuffix "-$(Agent.JobName)" -StageOnly
@@ -44,7 +48,7 @@ steps:
--secret '$(codesign_secret)'
--name 'Nerdbank.GitVersioning'
--descriptionUrl 'https://github.com/dotnet/Nerdbank.GitVersioning'
- displayName: Code sign
+ displayName: ๐ Code sign
condition: and(succeeded(), eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/'), eq(variables['Agent.OS'], 'Windows_NT'), ne(variables['Build.Reason'], 'PullRequest'))
- pwsh: >
@@ -57,21 +61,24 @@ steps:
--secret '$(codesign_secret)'
--name 'Nerdbank.GitVersioning'
--descriptionUrl 'https://github.com/dotnet/Nerdbank.GitVersioning'
- displayName: Code sign LKG
+ displayName: ๐ Code sign LKG
condition: and(succeeded(), eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/'), eq(variables['Agent.OS'], 'Windows_NT'), ne(variables['Build.Reason'], 'PullRequest'))
- powershell: azure-pipelines/variables/_pipelines.ps1
failOnStderr: true
- displayName: Update pipeline variables based on build outputs
+ displayName: โ Update pipeline variables based on build outputs
condition: succeededOrFailed()
-- powershell: azure-pipelines/artifacts/_pipelines.ps1 -ArtifactNameSuffix "-$(Agent.JobName)"
+- powershell: azure-pipelines/artifacts/_pipelines.ps1 -ArtifactNameSuffix "-$(Agent.JobName)" -Verbose
failOnStderr: true
- displayName: Publish artifacts
+ displayName: ๐ข Publish artifacts
condition: succeededOrFailed()
-- bash: bash <(curl -s https://codecov.io/bash)
- displayName: Publish code coverage results to codecov.io
- condition: ne(variables['codecov_token'], '')
- timeoutInMinutes: 3
- continueOnError: true
+- ${{ if and(ne(variables['codecov_token'], ''), parameters.RunTests) }}:
+ - powershell: |
+ $ArtifactStagingFolder = & "azure-pipelines/Get-ArtifactsStagingDirectory.ps1"
+ $CoverageResultsFolder = Join-Path $ArtifactStagingFolder "coverageResults-$(Agent.JobName)"
+ azure-pipelines/publish-CodeCov.ps1 -CodeCovToken "$(codecov_token)" -PathToCodeCoverage "$CoverageResultsFolder" -Name "$(Agent.JobName) Coverage Results" -Flags "$(Agent.JobName)Host,$(BuildConfiguration)"
+ displayName: ๐ข Publish code coverage results to codecov.io
+ timeoutInMinutes: 3
+ continueOnError: true
diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml
index 4f848b099..3993f1043 100644
--- a/azure-pipelines/install-dependencies.yml
+++ b/azure-pipelines/install-dependencies.yml
@@ -4,7 +4,7 @@ parameters:
steps:
- task: NuGetAuthenticate@0
- displayName: Authenticate NuGet feeds
+ displayName: ๐ Authenticate NuGet feeds
inputs:
forceReinstallCredentialProvider: true
@@ -17,9 +17,9 @@ steps:
if (Get-Command mono -ErrorAction SilentlyContinue) {
mono --version
}
- displayName: Install prerequisites
+ displayName: โ Install prerequisites
- powershell: azure-pipelines/variables/_pipelines.ps1
failOnStderr: true
- displayName: Set pipeline variables based on source
+ displayName: โ Set pipeline variables based on source
name: SetPipelineVariables
diff --git a/azure-pipelines/publish-CodeCov.ps1 b/azure-pipelines/publish-CodeCov.ps1
new file mode 100644
index 000000000..9926f0188
--- /dev/null
+++ b/azure-pipelines/publish-CodeCov.ps1
@@ -0,0 +1,30 @@
+<#
+.SYNOPSIS
+ Uploads code coverage to codecov.io
+.PARAMETER CodeCovToken
+ Code coverage token to use
+.PARAMETER PathToCodeCoverage
+ Path to root of code coverage files
+.PARAMETER Name
+ Name to upload with codecoverge
+.PARAMETER Flags
+ Flags to upload with codecoverge
+#>
+[CmdletBinding()]
+Param (
+ [Parameter(Mandatory=$true)]
+ [string]$CodeCovToken,
+ [Parameter(Mandatory=$true)]
+ [string]$PathToCodeCoverage,
+ [string]$Name,
+ [string]$Flags
+)
+
+$RepoRoot = (Resolve-Path "$PSScriptRoot/..").Path
+
+Get-ChildItem -Recurse -Path $PathToCodeCoverage -Filter "*.cobertura.xml" | % {
+ $relativeFilePath = Resolve-Path -relative $_.FullName
+
+ Write-Host "Uploading: $relativeFilePath" -ForegroundColor Yellow
+ & (& "$PSScriptRoot/Get-CodeCovTool.ps1") -t $CodeCovToken -f $relativeFilePath -R $RepoRoot -F $Flags -n $Name
+}
diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml
index 7be9459e5..7bf08b389 100644
--- a/azure-pipelines/publish-codecoverage.yml
+++ b/azure-pipelines/publish-codecoverage.yml
@@ -1,27 +1,17 @@
steps:
- download: current
artifact: coverageResults-Windows
- displayName: Download Windows code coverage results
+ displayName: ๐ป Download Windows code coverage results
continueOnError: true
- download: current
artifact: coverageResults-Linux
- displayName: Download Linux code coverage results
+ displayName: ๐ป Download Linux code coverage results
continueOnError: true
-- powershell: |
- dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.8.5 --configfile azure-pipelines/justnugetorg.nuget.config
- Copy-Item -Recurse $(Pipeline.Workspace)/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj
- Write-Host 'Substituting {reporoot} with $(System.DefaultWorkingDirectory)'
- $reports = Get-ChildItem -Recurse '$(Pipeline.Workspace)/coverage.*cobertura.xml'
- $reports |% {
- $content = Get-Content -Path $_ |% { $_.Replace('{reporoot}', '$(System.DefaultWorkingDirectory)') }
- Set-Content -Path $_ -Value $content -Encoding UTF8
- }
- $Inputs = [string]::join(';', ($reports |% { Resolve-Path -relative $_ }))
- obj/reportgenerator -reports:"$Inputs" -targetdir:coveragereport -reporttypes:Cobertura
- displayName: Merge coverage
+- powershell: azure-pipelines/Merge-CodeCoverage.ps1 -Path '$(Pipeline.Workspace)' -OutputDir coveragereport -Format Cobertura -Verbose
+ displayName: โ Merge coverage
- task: PublishCodeCoverageResults@1
- displayName: Publish code coverage results to Azure DevOps
+ displayName: ๐ข Publish code coverage results to Azure DevOps
inputs:
codeCoverageTool: cobertura
- summaryFileLocation: 'coveragereport/Cobertura.xml'
+ summaryFileLocation: coveragereport/Cobertura.xml
failIfCoverageEmpty: true
diff --git a/azure-pipelines/publish-deployables.yml b/azure-pipelines/publish-deployables.yml
index 6ad5b38cd..6e5e38038 100644
--- a/azure-pipelines/publish-deployables.yml
+++ b/azure-pipelines/publish-deployables.yml
@@ -1,17 +1,17 @@
steps:
- download: current
- displayName: Download deployables
+ displayName: ๐ป Download deployables
artifact: deployables-Windows
- powershell: dotnet nuget push "$(Resolve-Path '$(Pipeline.Workspace)\deployables-Windows\')*.nupkg" -s $(ci_feed) -k azdo --skip-duplicate
- displayName: Push packages to CI feed
+ displayName: ๐ฆ Push packages to CI feed
condition: and(succeeded(), ne(variables['ci_feed'], ''), ne(variables['Build.Reason'], 'PullRequest'))
- pwsh: Set-Content -Path "$(Agent.TempDirectory)/.npmrc" -Value "registry=$(ci_npm_feed)`nalways-auth=true"
- displayName: Prepare to push to PublicCI
+ displayName: โ๏ธ Prepare to push to PublicCI
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/'), ne(variables['Build.Reason'], 'PullRequest'))
- task: npmAuthenticate@0
- displayName: Authenticate to PublicCI
+ displayName: ๐ Authenticate to PublicCI
inputs:
workingFile: $(Agent.TempDirectory)/.npmrc
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/'), ne(variables['Build.Reason'], 'PullRequest'))
@@ -20,6 +20,6 @@ steps:
Write-Host "Will publish $tgz"
npm publish $tgz
workingDirectory: $(Agent.TempDirectory)
- displayName: npm publish to PublicCI feed
+ displayName: ๐ฆ npm publish to PublicCI feed
continueOnError: true
condition: and(succeeded(), ne(variables['ci_npm_feed'], ''), ne(variables['Build.Reason'], 'PullRequest'))
diff --git a/azure-pipelines/release.yml b/azure-pipelines/release.yml
index ed95d940b..e89ac6453 100644
--- a/azure-pipelines/release.yml
+++ b/azure-pipelines/release.yml
@@ -25,18 +25,18 @@ jobs:
} else {
Write-Host "##vso[task.setvariable variable=IsPrerelease]false"
}
- displayName: Set up pipeline
+ displayName: โ Set up pipeline
- task: UseDotNet@2
- displayName: Install .NET SDK
+ displayName: โ Install .NET SDK
inputs:
packageType: sdk
version: 6.x
- download: CI
artifact: deployables-Windows
- displayName: Download deployables-Windows artifact
+ displayName: ๐ป Download deployables-Windows artifact
patterns: 'deployables-Windows/*'
- task: GitHubRelease@1
- displayName: GitHub release (create)
+ displayName: ๐ข GitHub release (create)
inputs:
gitHubConnection: github.com_AArnott_OAuth
repositoryName: $(Build.Repository.Name)
@@ -51,12 +51,12 @@ jobs:
changeLogType: issueBased
changeLogLabels: |
[
- { "label" : "breaking changes", "displayName" : "Breaking changes", "state" : "closed" },
+ { "label" : "breaking change", "displayName" : "Breaking changes", "state" : "closed" },
{ "label" : "bug", "displayName" : "Fixes", "state" : "closed" },
{ "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" }
]
- script: dotnet nuget push $(Pipeline.Workspace)/CI/deployables-Windows/*.nupkg -s https://api.nuget.org/v3/index.json --api-key $(NuGetOrgApiKey) --skip-duplicate
- displayName: Push packages to nuget.org
+ displayName: ๐ฆ Push packages to nuget.org
condition: and(succeeded(), ne(variables['NuGetOrgApiKey'], ''))
- powershell: |
$tgz = (Get-ChildItem "$(Pipeline.Workspace)/CI/deployables-Windows/*.tgz")[0].FullName
@@ -64,9 +64,9 @@ jobs:
npm init -y
npm install $tgz
workingDirectory: $(Agent.TempDirectory)
- displayName: Prepare to publish NPM package
+ displayName: โ๏ธ Prepare to publish NPM package
- task: Npm@1
- displayName: npm publish
+ displayName: ๐ฆ npm publish
inputs:
command: publish
workingDir: $(Agent.TempDirectory)/node_modules/nerdbank-gitversioning
diff --git a/azure-pipelines/test.runsettings b/azure-pipelines/test.runsettings
new file mode 100644
index 000000000..c69022fc0
--- /dev/null
+++ b/azure-pipelines/test.runsettings
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+ \.dll$
+ \.exe$
+
+
+ xunit\..*
+
+
+
+
+ ^System\.Diagnostics\.DebuggerHiddenAttribute$
+ ^System\.Diagnostics\.DebuggerNonUserCodeAttribute$
+ ^System\.CodeDom\.Compiler\.GeneratedCodeAttribute$
+ ^System\.Diagnostics\.CodeAnalysis\.ExcludeFromCodeCoverageAttribute$
+
+
+
+
+ True
+
+ True
+
+ True
+
+ False
+
+ True
+
+ True
+
+ True
+
+
+
+
+
+
diff --git a/azure-pipelines/variables/_all.ps1 b/azure-pipelines/variables/_all.ps1
index 0407d307e..cc6e88105 100644
--- a/azure-pipelines/variables/_all.ps1
+++ b/azure-pipelines/variables/_all.ps1
@@ -1,7 +1,14 @@
#!/usr/bin/env pwsh
-# This script returns a hashtable of build variables that should be set
-# at the start of a build or release definition's execution.
+<#
+.SYNOPSIS
+ This script returns a hashtable of build variables that should be set
+ at the start of a build or release definition's execution.
+#>
+
+[CmdletBinding(SupportsShouldProcess = $true)]
+param (
+)
$vars = @{}
diff --git a/azure-pipelines/variables/_pipelines.ps1 b/azure-pipelines/variables/_pipelines.ps1
index 867b7fc8b..951106d2d 100644
--- a/azure-pipelines/variables/_pipelines.ps1
+++ b/azure-pipelines/variables/_pipelines.ps1
@@ -1,8 +1,15 @@
-# This script translates the variables returned by the _all.ps1 script
-# into commands that instruct Azure Pipelines to actually set those variables for other pipeline tasks to consume.
+<#
+.SYNOPSIS
+ This script translates the variables returned by the _all.ps1 script
+ into commands that instruct Azure Pipelines to actually set those variables for other pipeline tasks to consume.
-# The build or release definition may have set these variables to override
-# what the build would do. So only set them if they have not already been set.
+ The build or release definition may have set these variables to override
+ what the build would do. So only set them if they have not already been set.
+#>
+
+[CmdletBinding()]
+param (
+)
(& "$PSScriptRoot\_all.ps1").GetEnumerator() |% {
# Always use ALL CAPS for env var names since Azure Pipelines converts variable names to all caps and on non-Windows OS, env vars are case sensitive.
diff --git a/init.ps1 b/init.ps1
index 4d66f65bb..60a7010f2 100755
--- a/init.ps1
+++ b/init.ps1
@@ -33,8 +33,8 @@
#>
[CmdletBinding(SupportsShouldProcess = $true)]
Param (
- [ValidateSet('repo', 'machine')]
- [string]$InstallLocality = 'repo',
+ [ValidateSet('repo', 'user', 'machine')]
+ [string]$InstallLocality = 'user',
[Parameter()]
[switch]$NoPrerequisites,
[Parameter()]
diff --git a/test/Directory.Build.targets b/test/Directory.Build.targets
index 2faab3754..e7edee55a 100644
--- a/test/Directory.Build.targets
+++ b/test/Directory.Build.targets
@@ -1,10 +1,3 @@
-
- cobertura
- [xunit.*]*
-
- $(OutputPath)/
-
-
diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1
index 76a397f04..2bac3b9bc 100755
--- a/tools/Install-DotNetSdk.ps1
+++ b/tools/Install-DotNetSdk.ps1
@@ -80,7 +80,7 @@ Function Get-FileFromWeb([Uri]$Uri, $OutDir) {
$OutFile = Join-Path $OutDir $Uri.Segments[-1]
if (!(Test-Path $OutFile)) {
Write-Verbose "Downloading $Uri..."
- if (!(Test-Path $OutDir)) { New-Item -ItemType Directory -Path $OutDir }
+ if (!(Test-Path $OutDir)) { New-Item -ItemType Directory -Path $OutDir | Out-Null }
try {
(New-Object System.Net.WebClient).DownloadFile($Uri, $OutFile)
} finally {
@@ -91,35 +91,31 @@ Function Get-FileFromWeb([Uri]$Uri, $OutDir) {
$OutFile
}
-Function Get-InstallerExe($Version, $Architecture, [switch]$Runtime) {
- $sdkOrRuntime = 'Sdk'
- if ($Runtime) { $sdkOrRuntime = 'Runtime' }
-
+Function Get-InstallerExe(
+ $Version,
+ $Architecture,
+ [ValidateSet('Sdk','Runtime','WindowsDesktop')]
+ [string]$sku
+) {
# Get the latest/actual version for the specified one
$TypedVersion = [Version]$Version
if ($TypedVersion.Build -eq -1) {
- $versionInfo = -Split (Invoke-WebRequest -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/latest.version" -UseBasicParsing)
+ $versionInfo = -Split (Invoke-WebRequest -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sku/$Version/latest.version" -UseBasicParsing)
$Version = $versionInfo[-1]
}
$majorMinor = "$($TypedVersion.Major).$($TypedVersion.Minor)"
$ReleasesFile = Join-Path $DotNetInstallScriptRoot "$majorMinor\releases.json"
if (!(Test-Path $ReleasesFile)) {
- Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/$majorMinor/releases.json" -OutDir (Split-Path $ReleasesFile)
+ Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/$majorMinor/releases.json" -OutDir (Split-Path $ReleasesFile) | Out-Null
}
$releases = Get-Content $ReleasesFile | ConvertFrom-Json
$url = $null
foreach ($release in $releases.releases) {
$filesElement = $null
- if ($Runtime) {
- if ($release.runtime.version -eq $Version) {
- $filesElement = $release.runtime.files
- }
- } else {
- if ($release.sdk.version -eq $Version) {
- $filesElement = $release.sdk.files
- }
+ if ($release.$sku.version -eq $Version) {
+ $filesElement = $release.$sku.files
}
if ($filesElement) {
@@ -139,15 +135,14 @@ Function Get-InstallerExe($Version, $Architecture, [switch]$Runtime) {
if ($url) {
Get-FileFromWeb -Uri $url -OutDir $DotNetInstallScriptRoot
} else {
- Write-Error "Unable to find release of $sdkOrRuntime v$Version"
+ Write-Error "Unable to find release of $sku v$Version"
}
}
-Function Install-DotNet($Version, $Architecture, [switch]$Runtime) {
- if ($Runtime) { $sdkSubstring = '' } else { $sdkSubstring = 'SDK ' }
- Write-Host "Downloading .NET Core $sdkSubstring$Version..."
- $Installer = Get-InstallerExe -Version $Version -Architecture $Architecture -Runtime:$Runtime
- Write-Host "Installing .NET Core $sdkSubstring$Version..."
+Function Install-DotNet($Version, $Architecture, [ValidateSet('Sdk','Runtime','WindowsDesktop')][string]$sku = 'Sdk') {
+ Write-Host "Downloading .NET Core $sku $Version..."
+ $Installer = Get-InstallerExe -Version $Version -Architecture $Architecture -sku $sku
+ Write-Host "Installing .NET Core $sku $Version..."
cmd /c start /wait $Installer /install /passive /norestart
if ($LASTEXITCODE -eq 3010) {
Write-Verbose "Restart required"
@@ -177,13 +172,25 @@ if ($InstallLocality -eq 'machine') {
}
}
- $runtimeVersions | Get-Unique |% {
- if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) {
- Install-DotNet -Version $_ -Architecture $arch -Runtime
+ $runtimeVersions | Sort-Object | Get-Unique |% {
+ if ($PSCmdlet.ShouldProcess(".NET runtime $_", "Install")) {
+ Install-DotNet -Version $_ -sku Runtime -Architecture $arch
+ $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010)
+
+ if ($IncludeX86) {
+ Install-DotNet -Version $_ -sku Runtime -Architecture x86
+ $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010)
+ }
+ }
+ }
+
+ $windowsDesktopRuntimeVersions | Sort-Object | Get-Unique |% {
+ if ($PSCmdlet.ShouldProcess(".NET Windows Desktop $_", "Install")) {
+ Install-DotNet -Version $_ -sku WindowsDesktop -Architecture $arch
$restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010)
if ($IncludeX86) {
- Install-DotNet -Version $_ -Architecture x86 -Runtime
+ Install-DotNet -Version $_ -sku WindowsDesktop -Architecture x86
$restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010)
}
}
diff --git a/tools/Install-NuGetCredProvider.ps1 b/tools/Install-NuGetCredProvider.ps1
index 6d3100349..496049a29 100644
--- a/tools/Install-NuGetCredProvider.ps1
+++ b/tools/Install-NuGetCredProvider.ps1
@@ -33,7 +33,7 @@ if ($IsMacOS -or $IsLinux) {
$installerScript = Join-Path $toolsPath $installerScript
-if (!(Test-Path $installerScript)) {
+if (!(Test-Path $installerScript) -or $Force) {
Invoke-WebRequest $sourceUrl -OutFile $installerScript
}
@@ -43,7 +43,7 @@ if ($IsMacOS -or $IsLinux) {
chmod u+x $installerScript
}
-& $installerScript -Force:$Force
+& $installerScript -Force:$Force -AddNetfx -InstallNet6
if ($AccessToken) {
$endpoints = @()