diff --git a/eng/emitters/pipelines/templates/steps/create-apireview.yml b/eng/emitters/pipelines/templates/steps/create-apireview.yml index 5f46a82a712..6bedeee5fc2 100644 --- a/eng/emitters/pipelines/templates/steps/create-apireview.yml +++ b/eng/emitters/pipelines/templates/steps/create-apireview.yml @@ -5,6 +5,7 @@ parameters: ArtifactName: "packages" PackageName: "" LanguageShortName: "Unknown" + AzureServiceConnection: "APIView prod deployment" steps: # ideally this should be done as initial step of a job in caller template @@ -14,14 +15,16 @@ steps: # Automatic API review is generated for a package when pipeline runs irrespective of how pipeline gets triggered. # Below condition ensures that API review is generated only for manual pipeline runs when flag GenerateApiReviewForManualOnly is set to true. - ${{ if or(ne(parameters.GenerateApiReviewForManualOnly, true), eq(variables['Build.Reason'], 'Manual')) }}: - - task: Powershell@2 + - task: AzureCLI@2 inputs: - filePath: $(Build.SourcesDirectory)/eng/emitters/scripts/Create-APIReview.ps1 + azureSubscription: ${{ parameters.AzureServiceConnection }} + scriptType: pscore + scriptLocation: scriptPath + scriptPath: $(Build.SourcesDirectory)/eng/emitters/scripts/Create-APIReview.ps1 arguments: > -ArtifactList ('${{ convertToJson(parameters.Artifacts) }}' | ConvertFrom-Json | Select-Object Name) -ArtifactPath $(Agent.BuildDirectory)/${{ parameters.ArtifactName }} -ArtifactName ${{ parameters.ArtifactName }} - -APIKey $(azuresdk-apiview-apikey) -PackageName '${{parameters.PackageName}}' -SourceBranch $(Build.SourceBranchName) -DefaultBranch $(DefaultBranch) @@ -29,7 +32,6 @@ steps: -RepoName '$(Build.Repository.Name)' -MarkPackageAsShipped $${{parameters.MarkPackageAsShipped}} -LanguageShortName ${{parameters.LanguageShortName}} - pwsh: true workingDirectory: $(Pipeline.Workspace) displayName: Create API Review condition: >- diff --git a/eng/emitters/scripts/Create-APIReview.ps1 b/eng/emitters/scripts/Create-APIReview.ps1 index ddd091255d9..375b0464703 100644 --- a/eng/emitters/scripts/Create-APIReview.ps1 +++ b/eng/emitters/scripts/Create-APIReview.ps1 @@ -4,15 +4,13 @@ Param ( [array] $ArtifactList, [Parameter(Mandatory=$True)] [string] $ArtifactPath, - [Parameter(Mandatory=$True)] - [string] $APIKey, [string] $SourceBranch, [string] $DefaultBranch, [string] $RepoName, [string] $BuildId, [string] $PackageName = "", [string] $ConfigFileDir = "", - [string] $APIViewUri = "https://apiview.dev/AutoReview", + [string] $APIViewUri = "https://apiview.dev/autoreview", [string] $ArtifactName = "packages", [bool] $MarkPackageAsShipped = $false, [string] $LanguageShortName = "Unknown" @@ -22,6 +20,24 @@ Set-StrictMode -Version 3 . (Join-Path $PSScriptRoot ApiView-Helpers.ps1) . (Join-Path $PSScriptRoot SemVer.ps1) +# Get Bearer token for APIView authentication +# In Azure DevOps, this uses the service connection's Managed Identity/Service Principal +function Get-ApiViewBearerToken() +{ + try { + $tokenResponse = az account get-access-token --resource "api://apiview" --output json 2>&1 + if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to acquire access token. Please ensure Azure CLI is authenticated and has access to the APIView resource." + return $null + } + return ($tokenResponse | ConvertFrom-Json).accessToken + } + catch { + Write-Error "Failed to acquire access token: $($_.Exception.Message)" + return $null + } +} + if ($LanguageShortName -eq "Unknown") { Write-Host "Language short name is not provided. Please provide the language short name." @@ -86,9 +102,17 @@ function Upload-SourceArtifact($filePath, $apiLabel, $releaseStatus, $packageVer Write-Host "Request param, compareAllRevisions: true" } - $uri = "${APIViewUri}/UploadAutoReview" + $uri = "${APIViewUri}/upload" + + # Get Bearer token for authentication + $bearerToken = Get-ApiViewBearerToken + if (-not $bearerToken) { + Write-Error "Failed to acquire Bearer token for APIView authentication." + return [System.Net.HttpStatusCode]::Unauthorized + } + $headers = @{ - "ApiKey" = $apiKey; + "Authorization" = "Bearer $bearerToken"; "content-type" = "multipart/form-data" } @@ -100,7 +124,12 @@ function Upload-SourceArtifact($filePath, $apiLabel, $releaseStatus, $packageVer } catch { - Write-Host "Exception details: $($_.Exception.Response)" + Write-Host "ERROR: API request failed" -ForegroundColor Red + Write-Host "Status Code: $($_.Exception.Response.StatusCode.Value__)" -ForegroundColor Yellow + Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Yellow + if ($_.ErrorDetails.Message) { + Write-Host "Details: $($_.ErrorDetails.Message)" -ForegroundColor Yellow + } $StatusCode = $_.Exception.Response.StatusCode } @@ -118,26 +147,39 @@ function Upload-ReviewTokenFile($packageName, $apiLabel, $releaseStatus, $review if($MarkPackageAsShipped) { $params += "&setReleaseTag=true" } - $uri = "${APIViewUri}/CreateApiReview?${params}" + $uri = "${APIViewUri}/create?${params}" if ($releaseStatus -and ($releaseStatus -ne "Unreleased")) { $uri += "&compareAllRevisions=true" } Write-Host "Request to APIView: $uri" + + # Get Bearer token for authentication + $bearerToken = Get-ApiViewBearerToken + if (-not $bearerToken) { + Write-Error "Failed to acquire Bearer token for APIView authentication." + return [System.Net.HttpStatusCode]::Unauthorized + } + $headers = @{ - "ApiKey" = $APIKey; + "Authorization" = "Bearer $bearerToken" } try { - $Response = Invoke-WebRequest -Method 'GET' -Uri $uri -Headers $headers + $Response = Invoke-WebRequest -Method 'POST' -Uri $uri -Headers $headers Write-Host "API review: $($Response.Content)" $StatusCode = $Response.StatusCode } catch { - Write-Host "Exception details: $($_.Exception)" + Write-Host "ERROR: API request failed" -ForegroundColor Red + Write-Host "Status Code: $($_.Exception.Response.StatusCode.Value__)" -ForegroundColor Yellow + Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Yellow + if ($_.ErrorDetails.Message) { + Write-Host "Details: $($_.ErrorDetails.Message)" -ForegroundColor Yellow + } $StatusCode = $_.Exception.Response.StatusCode }