diff --git a/eng/common/scripts/get-codeowners.ps1 b/eng/common/scripts/get-codeowners.ps1 index fdf8453acee..dff01ecab60 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 } diff --git a/tools/code-owners-parser/Azure.Sdk.Tools.RetrieveCodeOwners.Tests/CODEOWNERS b/tools/code-owners-parser/Azure.Sdk.Tools.RetrieveCodeOwners.Tests/CODEOWNERS index 8c5af6a868f..d4a23d1bbb1 100644 --- a/tools/code-owners-parser/Azure.Sdk.Tools.RetrieveCodeOwners.Tests/CODEOWNERS +++ b/tools/code-owners-parser/Azure.Sdk.Tools.RetrieveCodeOwners.Tests/CODEOWNERS @@ -24,7 +24,10 @@ # PRLabel: %label /sdk/eventhubs/ @person7 @person8 +# This is for testing non user aliases case. +/sdk/testUser/ @azure/azure-sdk-eng @azure-sdk + # Example for service that does not have the code in the repo but wants issues to be labeled # Notice the use of the moniker // # ServiceLabel: %label %Service Attention -// @person7 @person8 \ No newline at end of file +// @person7 @person8 diff --git a/tools/code-owners-parser/ci.yml b/tools/code-owners-parser/ci.yml index 97068d14b7b..5e23a01c7a0 100644 --- a/tools/code-owners-parser/ci.yml +++ b/tools/code-owners-parser/ci.yml @@ -27,9 +27,10 @@ extends: ToolDirectory: tools/code-owners-parser DotNetCoreVersion: 5.0.301 TestPostSteps: - # This is a simple test for placeholder. Will replace the test with get-codeowners.ps1 in future. - - pwsh: | - $output = dotnet run --project "tools\code-owners-parser\Azure.Sdk.Tools.RetrieveCodeOwners\Azure.Sdk.Tools.RetrieveCodeOwners.csproj" ` - --code-owner-file-path "$(Build.SourcesDirectory)/tools/code-owners-parser/Azure.Sdk.Tools.RetrieveCodeOwners.Tests/CODEOWNERS" --target-directory "sdk" - $output | ConvertFrom-Json - displayName: Test on code owner tool output \ No newline at end of file + - task: PowerShell@2 + displayName: Test on code owner tool output + inputs: + pwsh: true + filePath: eng/common/scripts/get-codeowners.ps1 + arguments: > + -Test