From eb49b1dac65dfa93d0e4e0798fcea07c2ed407e5 Mon Sep 17 00:00:00 2001 From: Daniel Jurek Date: Fri, 17 Apr 2026 11:32:36 -0700 Subject: [PATCH 1/4] Add CODEOWNERS verification pipeline step and script Add verify-codeowners.yml pipeline template step and Test-CodeownersForArtifacts.ps1 script to validate that packages intended for release have sufficient CODEOWNERS coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../templates/steps/verify-codeowners.yml | 32 ++++++++++++ .../scripts/Test-CodeownersForArtifacts.ps1 | 49 +++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 eng/common/pipelines/templates/steps/verify-codeowners.yml create mode 100644 eng/common/scripts/Test-CodeownersForArtifacts.ps1 diff --git a/eng/common/pipelines/templates/steps/verify-codeowners.yml b/eng/common/pipelines/templates/steps/verify-codeowners.yml new file mode 100644 index 000000000000..fe163b657a07 --- /dev/null +++ b/eng/common/pipelines/templates/steps/verify-codeowners.yml @@ -0,0 +1,32 @@ +parameters: + - name: ArtifactPath + type: string + default: $(Build.ArtifactStagingDirectory)/PackageInfo + - name: Repo + type: string + default: $(Build.Repository.Name) + - name: SdkTypes + type: object + default: + - client + - compat + - data + - functions + - datamovement + +steps: + - template: /eng/common/pipelines/templates/steps/install-azsdk-cli.yml + parameters: + Condition: and(succeeded(), ne(variables['Skip.VerifyCodeowners'], 'true')) + + - task: PowerShell@2 + displayName: Verify Codeowners + condition: and(succeeded(), ne(variables['Skip.VerifyCodeowners'], 'true')) + inputs: + pwsh: true + filePath: eng/common/scripts/Test-CodeownersForArtifacts.ps1 + arguments: >- + -AzsdkPath '$(AZSDK)' + -PackageInfoDirectory '${{ parameters.ArtifactPath }}' + -SdkTypes ${{ join(',', parameters.SdkTypes) }} + -Repo '${{ parameters.Repo }}' diff --git a/eng/common/scripts/Test-CodeownersForArtifacts.ps1 b/eng/common/scripts/Test-CodeownersForArtifacts.ps1 new file mode 100644 index 000000000000..30943ec6c967 --- /dev/null +++ b/eng/common/scripts/Test-CodeownersForArtifacts.ps1 @@ -0,0 +1,49 @@ +param( + [string] $AzsdkPath, + [string] $PackageInfoDirectory, + [array] $SdkTypes, + [string] $Repo +) + +. "$PSScriptRoot/common.ps1" + +$failedPackages = @() + +foreach ($pkgPropertiesFile in Get-ChildItem -Path $PackageInfoDirectory -File) { + $pkgProperties = Get-Content -Raw -Path $pkgPropertiesFile | ConvertFrom-Json + if ($SdkTypes -notcontains $pkgProperties.SdkType) { + Write-Host "Skipping package: $($pkgProperties.Name) $($pkgProperties.DirectoryPath) because its SdkType '$($pkgProperties.SdkType)' is not in the list of SdkTypes to validate." + continue + } + + Write-Host "Validating codeowners for package: $($pkgProperties.Name) $($pkgProperties.DirectoryPath)" + + # Validate packages with a release date (intended to release) + if ($pkgProperties.ReleaseStatus -ne "Unreleased") { + $output = & $AzsdkPath config codeowners check-package ` + --directory-path $pkgProperties.DirectoryPath ` + --repo $Repo ` + --output json 2>&1 + + if ($LASTEXITCODE) { + LogError "Codeowners validation failed for package: $($pkgProperties.DirectoryPath)" + $output | Write-Host + $failedPackages += $pkgProperties.DirectoryPath + } else { + Write-Host " Codeowners validation succeeded for package: $($pkgProperties.DirectoryPath)" + } + } else { + Write-Host " Skipping CODEOWNERS validation, package is not intended to release." + } +} + +if ($failedPackages.Count -gt 0) { + Write-Host "" + Write-Host "Failed Packages:" + foreach ($directoryPath in $failedPackages) { + LogError " - $directoryPath does not have sufficient code owners coverage" + } + LogError "Codeowners validation failed for one or more packages. See http://aka.ms/azsdk/codeowners for instructions to fix the issue." + exit 1 +} +exit 0 From 1764e956a1c983e745cfefcbe4fac09641cdbbea Mon Sep 17 00:00:00 2001 From: Daniel Jurek Date: Fri, 17 Apr 2026 11:51:05 -0700 Subject: [PATCH 2/4] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- eng/common/pipelines/templates/steps/verify-codeowners.yml | 2 +- eng/common/scripts/Test-CodeownersForArtifacts.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/common/pipelines/templates/steps/verify-codeowners.yml b/eng/common/pipelines/templates/steps/verify-codeowners.yml index fe163b657a07..b272329bb375 100644 --- a/eng/common/pipelines/templates/steps/verify-codeowners.yml +++ b/eng/common/pipelines/templates/steps/verify-codeowners.yml @@ -24,7 +24,7 @@ steps: condition: and(succeeded(), ne(variables['Skip.VerifyCodeowners'], 'true')) inputs: pwsh: true - filePath: eng/common/scripts/Test-CodeownersForArtifacts.ps1 + filePath: $(Build.SourcesDirectory)/eng/common/scripts/Test-CodeownersForArtifacts.ps1 arguments: >- -AzsdkPath '$(AZSDK)' -PackageInfoDirectory '${{ parameters.ArtifactPath }}' diff --git a/eng/common/scripts/Test-CodeownersForArtifacts.ps1 b/eng/common/scripts/Test-CodeownersForArtifacts.ps1 index 30943ec6c967..19d1e9f864d2 100644 --- a/eng/common/scripts/Test-CodeownersForArtifacts.ps1 +++ b/eng/common/scripts/Test-CodeownersForArtifacts.ps1 @@ -9,7 +9,7 @@ param( $failedPackages = @() -foreach ($pkgPropertiesFile in Get-ChildItem -Path $PackageInfoDirectory -File) { +foreach ($pkgPropertiesFile in Get-ChildItem -Path $PackageInfoDirectory -Filter '*.json' -File) { $pkgProperties = Get-Content -Raw -Path $pkgPropertiesFile | ConvertFrom-Json if ($SdkTypes -notcontains $pkgProperties.SdkType) { Write-Host "Skipping package: $($pkgProperties.Name) $($pkgProperties.DirectoryPath) because its SdkType '$($pkgProperties.SdkType)' is not in the list of SdkTypes to validate." From 01b6f1cb5a417e8645679dabe97102d488ffafe9 Mon Sep 17 00:00:00 2001 From: Daniel Jurek Date: Fri, 17 Apr 2026 12:41:33 -0700 Subject: [PATCH 3/4] Review feedback --- eng/common/scripts/Test-CodeownersForArtifacts.ps1 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/eng/common/scripts/Test-CodeownersForArtifacts.ps1 b/eng/common/scripts/Test-CodeownersForArtifacts.ps1 index 19d1e9f864d2..d76b41d7a5a5 100644 --- a/eng/common/scripts/Test-CodeownersForArtifacts.ps1 +++ b/eng/common/scripts/Test-CodeownersForArtifacts.ps1 @@ -1,3 +1,4 @@ +[CmdletBinding()] param( [string] $AzsdkPath, [string] $PackageInfoDirectory, @@ -7,6 +8,9 @@ param( . "$PSScriptRoot/common.ps1" +Set-StrictMode -Version 3 +$ErrorActionPreference = 'Stop' + $failedPackages = @() foreach ($pkgPropertiesFile in Get-ChildItem -Path $PackageInfoDirectory -Filter '*.json' -File) { @@ -18,6 +22,11 @@ foreach ($pkgPropertiesFile in Get-ChildItem -Path $PackageInfoDirectory -Filter Write-Host "Validating codeowners for package: $($pkgProperties.Name) $($pkgProperties.DirectoryPath)" + if (!$pkgProperties.ReleaseStatus) { + LogWarning " Skipping CODEOWNERS validation for package: $($pkgProperties.Name) because it does not have a ReleaseStatus property." + continue + } + # Validate packages with a release date (intended to release) if ($pkgProperties.ReleaseStatus -ne "Unreleased") { $output = & $AzsdkPath config codeowners check-package ` From f2c61040855ef025bdc57fe000c6b19653c73b47 Mon Sep 17 00:00:00 2001 From: Daniel Jurek Date: Fri, 17 Apr 2026 12:44:37 -0700 Subject: [PATCH 4/4] Fail closed on missing release status --- eng/common/scripts/Test-CodeownersForArtifacts.ps1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/eng/common/scripts/Test-CodeownersForArtifacts.ps1 b/eng/common/scripts/Test-CodeownersForArtifacts.ps1 index d76b41d7a5a5..3c83173c21d2 100644 --- a/eng/common/scripts/Test-CodeownersForArtifacts.ps1 +++ b/eng/common/scripts/Test-CodeownersForArtifacts.ps1 @@ -22,9 +22,10 @@ foreach ($pkgPropertiesFile in Get-ChildItem -Path $PackageInfoDirectory -Filter Write-Host "Validating codeowners for package: $($pkgProperties.Name) $($pkgProperties.DirectoryPath)" - if (!$pkgProperties.ReleaseStatus) { - LogWarning " Skipping CODEOWNERS validation for package: $($pkgProperties.Name) because it does not have a ReleaseStatus property." - continue + if (!$pkgProperties.ReleaseStatus) { + LogError "Package $($pkgProperties.Name) at $($pkgProperties.DirectoryPath) is missing a ReleaseStatus property." + $failedPackages += $pkgProperties.DirectoryPath + continue } # Validate packages with a release date (intended to release)