Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 208 additions & 0 deletions .azdo/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,26 @@ stages:
dependenciesArtifactName: vcpkg-dependencies-x86
vcpkgCacheDir: '$(vcpkgCacheDir)'

- job: BuildPkg_Coverage_x64
displayName: Build Coverage Package (x64 Debug + /PROFILE)
pool:
vmImage: windows-latest
# Consumed only by the PR-only coverage job, so don't spend build time on
# branch builds (where CodeQL already competes for the agent budget).
condition: eq(variables['Build.Reason'], 'PullRequest')
# Non-gating: a coverage-specific build failure must never block the pipeline.
continueOnError: true
steps:
- template: ./templates/build-win32-openssh-job.yml
parameters:
nativeHostArch: x64
buildOutputDir: x64
artifactSuffix: Coverage-x64
dependenciesArtifactName: vcpkg-dependencies-x64
vcpkgCacheDir: '$(vcpkgCacheDir)'
configuration: Debug
linkerOptions: '/PROFILE'

- stage: Test
displayName: Test Win32-OpenSSH
dependsOn: Build
Expand Down Expand Up @@ -164,6 +184,194 @@ stages:
displayName: Clean up OpenSSH test environment
condition: always()

- job: CodeCoverageCore
pool:
vmImage: windows-latest
displayName: Win32-OpenSSH Code Coverage (Core)
# Coverage is informational and must never gate a merge while it stabilizes.
continueOnError: true
# Only run on pull requests. On branch builds CodeQL is enabled and the added
# coverage instrumentation overhead risks pushing the agent past its ~60 min timeout.
condition: eq(variables['Build.Reason'], 'PullRequest')
variables:
coverageDir: '$(Build.SourcesDirectory)/CodeCoverage'
steps:
- task: DownloadBuildArtifacts@0
displayName: 'Download coverage build artifacts (Debug + symbols)'
inputs:
buildType: current
downloadType: single
artifactName: Win32-OpenSSH-Coverage-x64
downloadPath: '$(System.ArtifactsDirectory)'

- task: DownloadBuildArtifacts@0
displayName: 'Download coverage unit test artifacts'
inputs:
buildType: current
downloadType: single
artifactName: UnitTests-Coverage-x64
downloadPath: '$(System.ArtifactsDirectory)'

- pwsh: |
Import-Module -Name "$(Build.SourcesDirectory)/contrib/win32/openssh/AzDOBuildTools" -Force
# Install the Debug (/PROFILE) build so Microsoft.CodeCoverage.Console can
# statically instrument the OpenSSH binaries and unit tests.
Install-OpenSSH -SourceDir "$(System.ArtifactsDirectory)/Win32-OpenSSH-Coverage-x64/x64/Debug" -OpenSSHDir "$env:SystemDrive/OpenSSH" -Verbose
Install-UnitTests -SourceDir "$(System.ArtifactsDirectory)/UnitTests-Coverage-x64/x64/Debug" -OpenSSHDir "$env:SystemDrive/OpenSSH" -Verbose
displayName: Install Win32-OpenSSH and unit tests

- pwsh: |
& "$(Build.SourcesDirectory)/contrib/win32/openssh/code_coverage/Invoke-AzDOCodeCoverage.ps1" `
-Suite Core `
-OpenSSHBinPath "$env:SystemDrive/OpenSSH" `
-SourceRoot "$(Build.SourcesDirectory)" `
-OutputDirectory "$(coverageDir)" -SkipAggregation -Verbose
displayName: Collect coverage - core tests (setup + unit + E2E)

- pwsh: |
if (Test-Path "$(coverageDir)")
{
$artifactName = 'Win32-OpenSSH-CodeCoverage-Core'
Write-Host "##vso[artifact.upload containerfolder=$artifactName;artifactname=$artifactName;]$(coverageDir)"
}
displayName: Upload core coverage artifact
condition: always()

- pwsh: |
Import-Module -Name "$(Build.SourcesDirectory)/contrib/win32/openssh/AzDOBuildTools" -Force
Clear-TestEnvironmentSetup
displayName: Clean up OpenSSH test environment
condition: always()

- job: CodeCoverageBash
pool:
vmImage: windows-latest
displayName: Win32-OpenSSH Code Coverage (Bash)
continueOnError: true
condition: eq(variables['Build.Reason'], 'PullRequest')
variables:
coverageDir: '$(Build.SourcesDirectory)/CodeCoverage'
steps:
- task: DownloadBuildArtifacts@0
displayName: 'Download coverage build artifacts (Debug + symbols)'
inputs:
buildType: current
downloadType: single
artifactName: Win32-OpenSSH-Coverage-x64
downloadPath: '$(System.ArtifactsDirectory)'

- task: DownloadBuildArtifacts@0
displayName: 'Download bash test config file artifact'
inputs:
buildType: current
downloadType: single
artifactName: ConfigFile-x64
downloadPath: '$(System.ArtifactsDirectory)'

- pwsh: |
Import-Module -Name "$(Build.SourcesDirectory)/contrib/win32/openssh/AzDOBuildTools" -Force
# Install the Debug (/PROFILE) build so the bash suite runs against
# instrumentable binaries with the sshd/ssh-agent services registered.
Install-OpenSSH -SourceDir "$(System.ArtifactsDirectory)/Win32-OpenSSH-Coverage-x64/x64/Debug" -OpenSSHDir "$env:SystemDrive/OpenSSH" -Verbose
displayName: Install Win32-OpenSSH

- pwsh: |
$configFileSrc = "$(System.ArtifactsDirectory)/ConfigFile-x64/config.h"
Copy-Item -Path $configFileSrc -Dest "$(Build.SourcesDirectory)" -Force
displayName: Copy config file artifact for bash tests

- pwsh: |
& "$(Build.SourcesDirectory)/contrib/win32/openssh/code_coverage/Invoke-AzDOCodeCoverage.ps1" `
-Suite Bash `
-OpenSSHBinPath "$env:SystemDrive/OpenSSH" `
-SourceRoot "$(Build.SourcesDirectory)" `
-OutputDirectory "$(coverageDir)" -SkipAggregation -Verbose
displayName: Collect coverage - bash tests

- pwsh: |
if (Test-Path "$(coverageDir)")
{
$artifactName = 'Win32-OpenSSH-CodeCoverage-Bash'
Write-Host "##vso[artifact.upload containerfolder=$artifactName;artifactname=$artifactName;]$(coverageDir)"
}
displayName: Upload bash coverage artifact
condition: always()

- pwsh: |
Import-Module -Name "$(Build.SourcesDirectory)/contrib/win32/openssh/AzDOBuildTools" -Force
Clear-TestEnvironmentSetup
displayName: Clean up OpenSSH test environment
condition: always()

- job: CodeCoverageAggregate
pool:
vmImage: windows-latest
displayName: Win32-OpenSSH Code Coverage (Aggregate)
# Run after both suite jobs regardless of their outcome (they are non-gating);
# aggregate whichever per-suite artifacts were produced.
dependsOn:
- CodeCoverageCore
- CodeCoverageBash
continueOnError: true
condition: eq(variables['Build.Reason'], 'PullRequest')
variables:
aggregateDir: '$(Build.SourcesDirectory)/CodeCoverage'
steps:
- task: DownloadBuildArtifacts@0
displayName: 'Download core coverage artifact'
continueOnError: true
inputs:
buildType: current
downloadType: single
artifactName: Win32-OpenSSH-CodeCoverage-Core
downloadPath: '$(System.ArtifactsDirectory)/coverage'

- task: DownloadBuildArtifacts@0
displayName: 'Download bash coverage artifact'
continueOnError: true
inputs:
buildType: current
downloadType: single
artifactName: Win32-OpenSSH-CodeCoverage-Bash
downloadPath: '$(System.ArtifactsDirectory)/coverage'

- pwsh: |
& "$(Build.SourcesDirectory)/contrib/win32/openssh/code_coverage/Invoke-AzDOCoverageAggregate.ps1" `
-InputDirectory "$(System.ArtifactsDirectory)/coverage" `
-OutputDirectory "$(aggregateDir)" `
-SourceRoot "$(Build.SourcesDirectory)" -Verbose
displayName: Aggregate per-suite coverage

- pwsh: |
$summary = Join-Path "$(aggregateDir)" 'coverage-summary.md'
if (Test-Path $summary) { Get-Content -Raw $summary }
displayName: Print coverage summary
condition: always()

- task: PublishCodeCoverageResults@2
displayName: Publish code coverage results
condition: always()
inputs:
# Publish the de-duplicated (per-source-file) report so the Azure
# DevOps "Code Coverage" widget headline matches the number we stand
# behind (see the "Print coverage summary" step). The native
# Microsoft.CodeCoverage.Console report counts each shared .c once per
# binary it is linked into, which inflates the totals ~3.6x. The native
# per-binary report (merged/merged.cobertura.xml) and the raw .coverage
# files are still uploaded in the Win32-OpenSSH-CodeCoverage artifact
# below for per-binary / per-method drill-down (e.g. in Visual Studio).
summaryFileLocation: '$(aggregateDir)/merged/merged-helper.cobertura.xml'
pathToSources: '$(Build.SourcesDirectory)'

- pwsh: |
if (Test-Path "$(aggregateDir)")
{
$artifactName = 'Win32-OpenSSH-CodeCoverage'
Write-Host "##vso[artifact.upload containerfolder=$artifactName;artifactname=$artifactName;]$(aggregateDir)"
}
displayName: Upload code coverage artifacts
condition: always()

- job: TestPkgWin32OpenSSHBash
pool:
vmImage: windows-latest
Expand Down
41 changes: 32 additions & 9 deletions .azdo/templates/build-win32-openssh-job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ parameters:
default: false
- name: vcpkgCacheDir
type: string
- name: configuration
type: string
default: Release
- name: linkerOptions
type: string
default: ''

steps:
- pwsh: |
Expand All @@ -32,23 +38,39 @@ steps:

- pwsh: |
$nativeArch = '${{ parameters.nativeHostArch }}'
$configuration = '${{ parameters.configuration }}'
$linkerOptions = '${{ parameters.linkerOptions }}'
Import-Module -Name "$(Build.SourcesDirectory)/contrib/win32/openssh/AzDOBuildTools" -Force
Invoke-AzDOBuild -NativeHostArch $nativeArch
displayName: Build Win32-OpenSSH (${{ parameters.nativeHostArch }})
if ($configuration -eq 'Release' -and -not $linkerOptions) {
Invoke-AzDOBuild -NativeHostArch $nativeArch
}
else {
# Coverage build: honor an alternate configuration (Debug) and inject
# extra linker options (e.g. /PROFILE for static instrumentation) via the
# linker's LINK environment variable, without editing any .vcxproj.
Import-Module -Name "$(Build.SourcesDirectory)/contrib/win32/openssh/OpenSSHBuildHelper.psm1" -Force
if ($linkerOptions) {
$env:LINK = ((@($env:LINK, $linkerOptions) | Where-Object { $_ }) -join ' ')
}
Start-OpenSSHBuild -Configuration $configuration -NativeHostArch $nativeArch -Verbose
}
displayName: Build Win32-OpenSSH (${{ parameters.nativeHostArch }} ${{ parameters.configuration }})
env:
VCPKG_BINARY_SOURCES: "clear;files,${{ parameters.vcpkgCacheDir }},readwrite"

- pwsh: |
$buildOutPath = "$(Build.SourcesDirectory)/bin"
$buildOutputDir = '${{ parameters.buildOutputDir }}'
$configuration = '${{ parameters.configuration }}'
$fullPath = Join-Path -Path $buildOutPath -ChildPath $buildOutputDir
$releasePath = Join-Path -Path $fullPath -ChildPath 'Release'
Get-ChildItem -Path $releasePath
$configPath = Join-Path -Path $fullPath -ChildPath $configuration
Get-ChildItem -Path $configPath
displayName: Capture build results (${{ parameters.artifactSuffix }})

- pwsh: |
$nativeArch = '${{ parameters.nativeHostArch }}'
$artifactSuffix = '${{ parameters.artifactSuffix }}'
$configuration = '${{ parameters.configuration }}'
$includeConfig = [System.Convert]::ToBoolean('${{ parameters.includeConfig }}')

Import-Module -Name "$(Build.SourcesDirectory)/contrib/win32/openssh/AzDOBuildTools" -Force
Expand All @@ -59,8 +81,8 @@ steps:
Remove-Item -Path $buildDestPath -Recurse -Force -ErrorAction SilentlyContinue
}
$null = New-Item -ItemType Directory -Path $buildDestPath -Force
$buildDestArchPath = Join-Path -Path $buildDestPath -ChildPath "$nativeArch/Release"
Copy-BuildResults -BuildResultsPath $buildDestArchPath -NativeHostArch $nativeArch -Configuration Release
$buildDestArchPath = Join-Path -Path $buildDestPath -ChildPath "$nativeArch/$configuration"
Copy-BuildResults -BuildResultsPath $buildDestArchPath -NativeHostArch $nativeArch -Configuration $configuration
#
# Upload build artifacts
Write-Verbose -Verbose -Message "Uploading build artifacts"
Expand All @@ -74,7 +96,7 @@ steps:
Remove-Item -Path $unitTestDestPath -Recurse -Force -ErrorAction SilentlyContinue
}
$null = New-Item -ItemType Directory -Path $unitTestDestPath -Force
Copy-UnitTests -UnitTestsSrcDir $buildOutPath -UnitTestsDestDir $unitTestDestPath -NativeHostArch $nativeArch -Configuration Release
Copy-UnitTests -UnitTestsSrcDir $buildOutPath -UnitTestsDestDir $unitTestDestPath -NativeHostArch $nativeArch -Configuration $configuration
#
# Upload unit test artifacts
Write-Verbose -Verbose -Message "Uploading unit test artifacts"
Expand All @@ -91,8 +113,9 @@ steps:
displayName: Upload Win32-OpenSSH build artifacts (${{ parameters.artifactSuffix }})

- pwsh: |
$artifactSuffix = '${{ parameters.artifactSuffix }}'
$logFileName = "OpenSSHRelease$artifactSuffix.log"
$nativeArch = '${{ parameters.nativeHostArch }}'
$configuration = '${{ parameters.configuration }}'
$logFileName = "OpenSSH$configuration$nativeArch.log"
$uniqueLines = [System.Collections.Generic.HashSet[string]]::new()
$logFilePath = "$(Build.SourcesDirectory)/contrib/win32/openssh/$logFileName"
if (Test-Path -Path $logFilePath) {
Expand Down
Loading