diff --git a/eng/common/scripts/get-codeowners.ps1 b/eng/common/scripts/get-codeowners.ps1 index fdf8453aceeb..dff01ecab607 100644 --- a/eng/common/scripts/get-codeowners.ps1 +++ b/eng/common/scripts/get-codeowners.ps1 @@ -1,49 +1,91 @@ param ( - $TargetDirectory, # should be in relative form from root of repo. EG: sdk/servicebus - $RootDirectory, # ideally $(Build.SourcesDirectory) - $VsoVariable = "" # target devops output variable + [string]$TargetDirectory = "", # Code path to code owners. e.g sdk/core/azure-amqp + [string]$CodeOwnerFileLocation = "$PSSCriptRoot/../../../.github/CODEOWNERS", # The absolute path of CODEOWNERS file. + [string]$ToolVersion = "1.0.0-dev.20211122.14", # Placeholder. Will update in next PR + [string]$ToolPath = (Join-Path ([System.IO.Path]::GetTempPath()) "codeowners-tool-path"), # The place to check the tool existence. Put temp path as default + [string]$DevOpsFeed = "https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json", # DevOp tool feeds. + [string]$VsoVariable = "", # Option of write code owners into devop variable + [switch]$IncludeNonUserAliases, # Option to filter out the team alias in code owner list. e.g. Azure/azure-sdk-team + [switch]$Test #Run test functions against the script logic ) -$target = $TargetDirectory.ToLower().Trim("/") -$codeOwnersLocation = Join-Path $RootDirectory -ChildPath ".github/CODEOWNERS" -$ownedFolders = @{} -if (!(Test-Path $codeOwnersLocation)) { - Write-Host "Unable to find CODEOWNERS file in target directory $RootDirectory" - exit 1 -} - -$codeOwnersContent = Get-Content $codeOwnersLocation +function Get-CodeOwnersTool() +{ + $command = Join-Path $ToolPath "retrieve-codeowners" + # Check if the retrieve-codeowners tool exsits or not. + if (Get-Command $command -errorAction SilentlyContinue) { + return $command + } + if (!(Test-Path $ToolPath)) { + New-Item -ItemType Directory -Path $ToolPath | Out-Null + } + Write-Host "Installing the retrieve-codeowners tool under $ToolPath... " + dotnet tool install --tool-path $ToolPath --add-source $DevOpsFeed --version $ToolVersion "Azure.Sdk.Tools.RetrieveCodeOwners" | Out-Null -foreach ($contentLine in $codeOwnersContent) { - if (-not $contentLine.StartsWith("#") -and $contentLine){ - $splitLine = $contentLine -split "\s+" - - # CODEOWNERS file can also have labels present after the owner aliases - # gh aliases start with @ in codeowners. don't pass on to API calls - $ownedFolders[$splitLine[0].ToLower().Trim("/")] = ($splitLine[1..$($splitLine.Length)] ` - | ? { $_.StartsWith("@") } ` - | % { return $_.substring(1) }) -join "," + # Test to see if the tool properly installed. + if (!(Get-Command $command -errorAction SilentlyContinue)) { + Write-Error "The retrieve-codeowners tool is not properly installed. Please check your tool path. $ToolPath" + return } + return $command } -$results = $ownedFolders[$target] - -if ($results) { - Write-Host "Found a folder $results to match $target" +function Get-CodeOwners ([string]$targetDirectory, [string]$codeOwnerFileLocation, [bool]$includeNonUserAliases = $false) +{ + $command = Get-CodeOwnersTool + # Filter out the non user alias from code owner list. + Write-Host "Testing on $targetDirectory..." + if($includeNonUserAliases) { + $codeOwnersString = & $command --target-directory $targetDirectory --code-owner-file-path $codeOwnerFileLocation 2>&1 + } + else { + $codeOwnersString = & $command --target-directory $targetDirectory --code-owner-file-path $codeOwnerFileLocation --filter-out-non-user-aliases 2>&1 + } + # Failed at the command of fetching code owners. + if ($LASTEXITCODE -ne 0) { + Write-Host $codeOwnersString + return ,@() + } + + $codeOwnersJson = $codeOwnersString | ConvertFrom-Json + if (!$codeOwnersJson) { + Write-Host "No code owners returned from the path: $targetDirectory" + return ,@() + } if ($VsoVariable) { - $alreadyPresent = [System.Environment]::GetEnvironmentVariable($VsoVariable) + $codeOwners = $codeOwnersJson.Owners -join "," + Write-Host "##vso[task.setvariable variable=$VsoVariable;]$codeOwners" + } + + return ,@($codeOwnersJson.Owners) +} + +function TestGetCodeOwner([string]$targetDirectory, [string]$codeOwnerFileLocation, [bool]$includeNonUserAliases = $false, [string[]]$expectReturn) { + $actualReturn = Get-CodeOwners -targetDirectory $targetDirectory -codeOwnerFileLocation $codeOwnerFileLocation -includeNonUserAliases $IncludeNonUserAliases - if ($alreadyPresent) { - $results += ",$alreadyPresent" + if ($actualReturn.Count -ne $expectReturn.Count) { + Write-Error "The length of actual result is not as expected. Expected length: $($expectReturn.Count), Actual length: $($actualReturn.Count)." + exit 1 + } + for ($i = 0; $i -lt $expectReturn.Count; $i++) { + if ($expectReturn[$i] -ne $actualReturn[$i]) { + Write-Error "Expect result $expectReturn[$i] is different than actual result $actualReturn[$i]." + exit 1 } - Write-Host "##vso[task.setvariable variable=$VsoVariable;]$results" } +} - return $results +if($Test) { + $testFile = "$PSSCriptRoot/../../../tools/code-owners-parser/Azure.Sdk.Tools.RetrieveCodeOwners.Tests/CODEOWNERS" + TestGetCodeOwner -targetDirectory "sdk" -codeOwnerFileLocation $testFile -includeNonUserAliases $true -expectReturn @("person1", "person2") + TestGetCodeOwner -targetDirectory "sdk/noPath" -codeOwnerFileLocation $testFile -includeNonUserAliases $true -expectReturn @("person1", "person2") + TestGetCodeOwner -targetDirectory "/sdk/azconfig" -codeOwnerFileLocation $testFile -includeNonUserAliases $true -expectReturn @("person3", "person4") + TestGetCodeOwner -targetDirectory "/sdk/azconfig/package" -codeOwnerFileLocation $testFile -includeNonUserAliases $true $testFile -expectReturn @("person3", "person4") + TestGetCodeOwner -targetDirectory "/sd" -codeOwnerFileLocation $testFile -includeNonUserAliases $true -expectReturn @() + TestGetCodeOwner -targetDirectory "/sdk/testUser/" -codeOwnerFileLocation $testFile -expectReturn @("azure-sdk") + exit 0 } else { - Write-Host "Unable to match path $target in CODEOWNERS file located at $codeOwnersLocation." - Write-Host ($ownedFolders | ConvertTo-Json) - return "" + return Get-CodeOwners -targetDirectory $TargetDirectory -codeOwnerFileLocation $CodeOwnerFileLocation -includeNonUserAliases $IncludeNonUserAliases }