From 7fa626d47caf0c744602a1571185227779e5fe4d Mon Sep 17 00:00:00 2001 From: Azure SDK Bot <53356347+azure-sdk@users.noreply.github.com> Date: Wed, 27 Mar 2024 15:01:11 -0400 Subject: [PATCH] Sync eng/common directory with azure-sdk-tools for PR 7855 (#5459) * Pipeline template to validate package and update package work item * Changes to restructure validations * Additional fixes as per comments * Remove explicit exit code * Set erroractionpreference for change log check --------- Co-authored-by: Praveen Kuttappan --- .../templates/steps/validate-all-packages.yml | 34 +++ eng/common/scripts/ChangeLog-Operations.ps1 | 73 +++-- .../scripts/Helpers/ApiView-Helpers.ps1 | 18 +- .../Helpers/DevOps-WorkItem-Helpers.ps1 | 42 +++ .../Update-DevOps-Release-WorkItem.ps1 | 10 +- eng/common/scripts/Validate-All-Packages.ps1 | 52 ++++ eng/common/scripts/Validate-Package.ps1 | 252 ++++++++++++++++++ 7 files changed, 447 insertions(+), 34 deletions(-) create mode 100644 eng/common/pipelines/templates/steps/validate-all-packages.yml create mode 100644 eng/common/scripts/Validate-All-Packages.ps1 create mode 100644 eng/common/scripts/Validate-Package.ps1 diff --git a/eng/common/pipelines/templates/steps/validate-all-packages.yml b/eng/common/pipelines/templates/steps/validate-all-packages.yml new file mode 100644 index 000000000..db374478a --- /dev/null +++ b/eng/common/pipelines/templates/steps/validate-all-packages.yml @@ -0,0 +1,34 @@ +parameters: + ArtifactPath: $(Build.ArtifactStagingDirectory) + Artifacts: [] + ConfigFileDir: $(Build.ArtifactStagingDirectory)/PackageInfo + +steps: + - ${{ if and(ne(variables['Skip.PackageValidation'], 'true'), eq(variables['System.TeamProject'], 'internal')) }}: + - pwsh: | + echo "##vso[task.setvariable variable=SetAsReleaseBuild]false" + displayName: "Set as release build" + condition: and(succeeded(), eq(variables['SetAsReleaseBuild'], '')) + + - task: Powershell@2 + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/scripts/Validate-All-Packages.ps1 + arguments: > + -ArtifactList ('${{ convertToJson(parameters.Artifacts) }}' | ConvertFrom-Json | Select-Object Name) + -ArtifactPath ${{ parameters.ArtifactPath }} + -RepoRoot $(Build.SourcesDirectory) + -APIKey $(azuresdk-apiview-apikey) + -ConfigFileDir '${{ parameters.ConfigFileDir }}' + -BuildDefinition $(System.CollectionUri)$(System.TeamProject)/_build?definitionId=$(System.DefinitionId) + -PipelineUrl $(System.CollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId) + -Devops_pat '$(azuresdk-azure-sdk-devops-release-work-item-pat)' + -IsReleaseBuild $$(SetAsReleaseBuild) + pwsh: true + workingDirectory: $(Pipeline.Workspace) + displayName: Validate packages and update work items + continueOnError: true + condition: >- + and( + succeededOrFailed(), + not(endsWith(variables['Build.Repository.Name'], '-pr')) + ) diff --git a/eng/common/scripts/ChangeLog-Operations.ps1 b/eng/common/scripts/ChangeLog-Operations.ps1 index e31d10dc8..fb5f85c9a 100644 --- a/eng/common/scripts/ChangeLog-Operations.ps1 +++ b/eng/common/scripts/ChangeLog-Operations.ps1 @@ -138,14 +138,27 @@ function Confirm-ChangeLogEntry { [Parameter(Mandatory = $true)] [String]$VersionString, [boolean]$ForRelease = $false, - [Switch]$SantizeEntry + [Switch]$SantizeEntry, + [PSCustomObject]$ChangeLogStatus = $null ) + if (!$ChangeLogStatus) { + $ChangeLogStatus = [PSCustomObject]@{ + IsValid = $false + Message = "" + } + } + else { + # Do not stop the script on error when status object is passed as param + $ErrorActionPreference = 'Continue' + } $changeLogEntries = Get-ChangeLogEntries -ChangeLogLocation $ChangeLogLocation $changeLogEntry = $changeLogEntries[$VersionString] if (!$changeLogEntry) { - LogError "ChangeLog[${ChangeLogLocation}] does not have an entry for version ${VersionString}." + $ChangeLogStatus.Message = "ChangeLog[${ChangeLogLocation}] does not have an entry for version ${VersionString}." + $ChangeLogStatus.IsValid = $false + LogError "$($ChangeLogStatus.Message)" return $false } @@ -161,14 +174,16 @@ function Confirm-ChangeLogEntry { Write-Host "-----" if ([System.String]::IsNullOrEmpty($changeLogEntry.ReleaseStatus)) { - LogError "Entry does not have a correct release status. Please ensure the status is set to a date '($CHANGELOG_DATE_FORMAT)' or '$CHANGELOG_UNRELEASED_STATUS' if not yet released. See https://aka.ms/azsdk/guideline/changelogs for more info." + $ChangeLogStatus.Message = "Entry does not have a release status. Please ensure the status is set to a date '($CHANGELOG_DATE_FORMAT)' or '$CHANGELOG_UNRELEASED_STATUS' if not yet released. See https://aka.ms/azsdk/guideline/changelogs for more info." + $ChangeLogStatus.IsValid = $false + LogError "$($ChangeLogStatus.Message)" return $false } if ($ForRelease -eq $True) { LogDebug "Verifying as a release build because ForRelease parameter is set to true" - return Confirm-ChangeLogForRelease -changeLogEntry $changeLogEntry -changeLogEntries $changeLogEntries + return Confirm-ChangeLogForRelease -changeLogEntry $changeLogEntry -changeLogEntries $changeLogEntries -ChangeLogStatus $ChangeLogStatus } # If the release status is a valid date then verify like its about to be released @@ -176,9 +191,11 @@ function Confirm-ChangeLogEntry { if ($status -as [DateTime]) { LogDebug "Verifying as a release build because the changelog entry has a valid date." - return Confirm-ChangeLogForRelease -changeLogEntry $changeLogEntry -changeLogEntries $changeLogEntries + return Confirm-ChangeLogForRelease -changeLogEntry $changeLogEntry -changeLogEntries $changeLogEntries -ChangeLogStatus $ChangeLogStatus } + $ChangeLogStatus.Message = "ChangeLog[${ChangeLogLocation}] has an entry for version ${VersionString}." + $ChangeLogStatus.IsValid = $true return $true } @@ -338,15 +355,23 @@ function Confirm-ChangeLogForRelease { [Parameter(Mandatory = $true)] $changeLogEntry, [Parameter(Mandatory = $true)] - $changeLogEntries + $changeLogEntries, + $ChangeLogStatus = $null ) + if (!$ChangeLogStatus) { + $ChangeLogStatus = [PSCustomObject]@{ + IsValid = $false + Message = "" + } + } $entries = Sort-ChangeLogEntries -changeLogEntries $changeLogEntries - $isValid = $true + $ChangeLogStatus.IsValid = $true if ($changeLogEntry.ReleaseStatus -eq $CHANGELOG_UNRELEASED_STATUS) { - LogError "Entry has no release date set. Please ensure to set a release date with format '$CHANGELOG_DATE_FORMAT'. See https://aka.ms/azsdk/guideline/changelogs for more info." - $isValid = $false + $ChangeLogStatus.Message = "Entry has no release date set. Please ensure to set a release date with format '$CHANGELOG_DATE_FORMAT'. See https://aka.ms/azsdk/guideline/changelogs for more info." + $ChangeLogStatus.IsValid = $false + LogError "$($ChangeLogStatus.Message)" } else { $status = $changeLogEntry.ReleaseStatus.Trim().Trim("()") @@ -354,25 +379,29 @@ function Confirm-ChangeLogForRelease { $releaseDate = [DateTime]$status if ($status -ne ($releaseDate.ToString($CHANGELOG_DATE_FORMAT))) { - LogError "Date must be in the format $($CHANGELOG_DATE_FORMAT). See https://aka.ms/azsdk/guideline/changelogs for more info." - $isValid = $false + $ChangeLogStatus.Message = "Date must be in the format $($CHANGELOG_DATE_FORMAT). See https://aka.ms/azsdk/guideline/changelogs for more info." + $ChangeLogStatus.IsValid = $false + LogError "$($ChangeLogStatus.Message)" } if (@($entries.ReleaseStatus)[0] -ne $changeLogEntry.ReleaseStatus) { - LogError "Invalid date [ $status ]. The date for the changelog being released must be the latest in the file." - $isValid = $false + $ChangeLogStatus.Message = "Invalid date [ $status ]. The date for the changelog being released must be the latest in the file." + $ChangeLogStatus.IsValid = $false + LogError "$($ChangeLogStatus.Message)" } } catch { - LogError "Invalid date [ $status ] passed as status for Version [$($changeLogEntry.ReleaseVersion)]. See https://aka.ms/azsdk/guideline/changelogs for more info." - $isValid = $false + $ChangeLogStatus.Message = "Invalid date [ $status ] passed as status for Version [$($changeLogEntry.ReleaseVersion)]. See https://aka.ms/azsdk/guideline/changelogs for more info." + $ChangeLogStatus.IsValid = $false + LogError "$($ChangeLogStatus.Message)" } } if ([System.String]::IsNullOrWhiteSpace($changeLogEntry.ReleaseContent)) { - LogError "Entry has no content. Please ensure to provide some content of what changed in this version. See https://aka.ms/azsdk/guideline/changelogs for more info." - $isValid = $false + $ChangeLogStatus.Message = "Entry has no content. Please ensure to provide some content of what changed in this version. See https://aka.ms/azsdk/guideline/changelogs for more info." + $ChangeLogStatus.IsValid = $false + LogError "$($ChangeLogStatus.Message)" } $foundRecommendedSection = $false @@ -391,12 +420,14 @@ function Confirm-ChangeLogForRelease { } if ($emptySections.Count -gt 0) { - LogError "The changelog entry has the following sections with no content ($($emptySections -join ', ')). Please ensure to either remove the empty sections or add content to the section." - $isValid = $false + $ChangeLogStatus.Message = "The changelog entry has the following sections with no content ($($emptySections -join ', ')). Please ensure to either remove the empty sections or add content to the section." + $ChangeLogStatus.IsValid = $false + LogError "$($ChangeLogStatus.Message)" } if (!$foundRecommendedSection) { - LogWarning "The changelog entry did not contain any of the recommended sections ($($RecommendedSectionHeaders -join ', ')), please add at least one. See https://aka.ms/azsdk/guideline/changelogs for more info." + $ChangeLogStatus.Message = "The changelog entry did not contain any of the recommended sections ($($RecommendedSectionHeaders -join ', ')), please add at least one. See https://aka.ms/azsdk/guideline/changelogs for more info." + LogWarning "$($ChangeLogStatus.Message)" } - return $isValid + return $ChangeLogStatus.IsValid } \ No newline at end of file diff --git a/eng/common/scripts/Helpers/ApiView-Helpers.ps1 b/eng/common/scripts/Helpers/ApiView-Helpers.ps1 index bf8b16a99..58ee8ee19 100644 --- a/eng/common/scripts/Helpers/ApiView-Helpers.ps1 +++ b/eng/common/scripts/Helpers/ApiView-Helpers.ps1 @@ -1,4 +1,4 @@ -function MapLanguageName($language) +function MapLanguageToRequestParam($language) { $lang = $language # Update language name to match those in API cosmos DB. Cosmos SQL is case sensitive and handling this within the query makes it slow. @@ -6,7 +6,7 @@ function MapLanguageName($language) $lang = "JavaScript" } elseif ($lang -eq "dotnet"){ - $lang = "C#" + $lang = "C%23" } elseif ($lang -eq "java"){ $lang = "Java" @@ -23,17 +23,12 @@ function MapLanguageName($language) function Check-ApiReviewStatus($packageName, $packageVersion, $language, $url, $apiKey, $apiApprovalStatus = $null, $packageNameStatus = $null) { # Get API view URL and API Key to check status - Write-Host "Checking API review status" - $lang = MapLanguageName -language $language + Write-Host "Checking API review status for package: ${packageName}" + $lang = MapLanguageToRequestParam -language $language if ($lang -eq $null) { return } $headers = @{ "ApiKey" = $apiKey } - $body = @{ - language = $lang - packageName = $packageName - packageVersion = $packageVersion - } if (!$apiApprovalStatus) { $apiApprovalStatus = [PSCustomObject]@{ @@ -51,7 +46,10 @@ function Check-ApiReviewStatus($packageName, $packageVersion, $language, $url, $ try { - $response = Invoke-WebRequest $url -Method 'GET' -Headers $headers -Body $body + $requestUrl = "${url}?language=${lang}&packageName=${packageName}&packageVersion=${packageVersion}" + Write-Host "Request to APIView: [${requestUrl}]" + $response = Invoke-WebRequest $requestUrl -Method 'GET' -Headers $headers + Write-Host "Response: $($response.StatusCode)" Process-ReviewStatusCode -statusCode $response.StatusCode -packageName $packageName -apiApprovalStatus $apiApprovalStatus -packageNameStatus $packageNameStatus if ($apiApprovalStatus.IsApproved) { Write-Host $($apiApprovalStatus.Details) diff --git a/eng/common/scripts/Helpers/DevOps-WorkItem-Helpers.ps1 b/eng/common/scripts/Helpers/DevOps-WorkItem-Helpers.ps1 index c03b6693e..805486245 100644 --- a/eng/common/scripts/Helpers/DevOps-WorkItem-Helpers.ps1 +++ b/eng/common/scripts/Helpers/DevOps-WorkItem-Helpers.ps1 @@ -985,4 +985,46 @@ function UpdatePackageVersions($pkgWorkItem, $plannedVersions, $shippedVersions) -Uri "https://dev.azure.com/azure-sdk/_apis/wit/workitems/${id}?api-version=6.0" ` -Headers (Get-DevOpsRestHeaders) -Body $body -ContentType "application/json-patch+json" | ConvertTo-Json -Depth 10 | ConvertFrom-Json -AsHashTable return $response +} + +function UpdateValidationStatus($pkgvalidationDetails, $BuildDefinition, $PipelineUrl) +{ + $pkgName = $pkgValidationDetails.Name + $versionString = $pkgValidationDetails.Version + + $parsedNewVersion = [AzureEngSemanticVersion]::new($versionString) + $versionMajorMinor = "" + $parsedNewVersion.Major + "." + $parsedNewVersion.Minor + $workItem = FindPackageWorkItem -lang $LanguageDisplayName -packageName $pkgName -version $versionMajorMinor -includeClosed $true -outputCommand $false + + if (!$workItem) + { + Write-Host"No work item found for package [$pkgName]." + return $false + } + + $changeLogStatus = $pkgValidationDetails.ChangeLogValidation.Status + $changeLogDetails = $pkgValidationDetails.ChangeLogValidation.Message + $apiReviewStatus = $pkgValidationDetails.APIReviewValidation.Status + $apiReviewDetails = $pkgValidationDetails.APIReviewValidation.Message + $packageNameStatus = $pkgValidationDetails.PackageNameValidation.Status + $packageNameDetails = $pkgValidationDetails.PackageNameValidation.Message + + $fields = @() + $fields += "`"PackageVersion=${versionString}`"" + $fields += "`"ChangeLogStatus=${changeLogStatus}`"" + $fields += "`"ChangeLogValidationDetails=${changeLogDetails}`"" + $fields += "`"APIReviewStatus=${apiReviewStatus}`"" + $fields += "`"APIReviewStatusDetails=${apiReviewDetails}`"" + $fields += "`"PackageNameApprovalStatus=${packageNameStatus}`"" + $fields += "`"PackageNameApprovalDetails=${packageNameDetails}`"" + if ($BuildDefinition) { + $fields += "`"PipelineDefinition=$BuildDefinition`"" + } + if ($PipelineUrl) { + $fields += "`"LatestPipelineRun=$PipelineUrl`"" + } + + $workItem = UpdateWorkItem -id $workItem.id -fields $fields + Write-Host "[$($workItem.id)]$LanguageDisplayName - $pkgName($versionMajorMinor) - Updated" + return $true } \ No newline at end of file diff --git a/eng/common/scripts/Update-DevOps-Release-WorkItem.ps1 b/eng/common/scripts/Update-DevOps-Release-WorkItem.ps1 index c8ac48e4f..b3a0da803 100644 --- a/eng/common/scripts/Update-DevOps-Release-WorkItem.ps1 +++ b/eng/common/scripts/Update-DevOps-Release-WorkItem.ps1 @@ -15,7 +15,8 @@ param( [string]$packageNewLibrary = "true", [string]$relatedWorkItemId = $null, [string]$tag = $null, - [string]$devops_pat = $env:DEVOPS_PAT + [string]$devops_pat = $env:DEVOPS_PAT, + [bool]$inRelease = $true ) #Requires -Version 6.0 Set-StrictMode -Version 3 @@ -97,8 +98,11 @@ Write-Host " PackageDisplayName: $($workItem.fields['Custom.PackageDisplayName' Write-Host " ServiceName: $($workItem.fields['Custom.ServiceName'])" Write-Host " PackageType: $($workItem.fields['Custom.PackageType'])" Write-Host "" -Write-Host "Marking item [$($workItem.id)]$($workItem.fields['System.Title']) as '$state' for '$releaseType'" -$updatedWI = UpdatePackageWorkItemReleaseState -id $workItem.id -state "In Release" -releaseType $releaseType -outputCommand $false +if ($inRelease) +{ + Write-Host "Marking item [$($workItem.id)]$($workItem.fields['System.Title']) as '$state' for '$releaseType'" + $updatedWI = UpdatePackageWorkItemReleaseState -id $workItem.id -state "In Release" -releaseType $releaseType -outputCommand $false +} $updatedWI = UpdatePackageVersions $workItem -plannedVersions $plannedVersions Write-Host "Release tracking item is at https://dev.azure.com/azure-sdk/Release/_workitems/edit/$($updatedWI.id)/" diff --git a/eng/common/scripts/Validate-All-Packages.ps1 b/eng/common/scripts/Validate-All-Packages.ps1 new file mode 100644 index 000000000..46d76195b --- /dev/null +++ b/eng/common/scripts/Validate-All-Packages.ps1 @@ -0,0 +1,52 @@ +[CmdletBinding()] +Param ( + [Parameter(Mandatory=$True)] + [array]$ArtifactList, + [Parameter(Mandatory=$True)] + [string]$ArtifactPath, + [Parameter(Mandatory=$True)] + [string]$RepoRoot, + [Parameter(Mandatory=$True)] + [string]$APIKey, + [string]$ConfigFileDir, + [string]$BuildDefinition, + [string]$PipelineUrl, + [string]$APIViewUri = "https://apiview.dev/AutoReview/GetReviewStatus", + [string]$Devops_pat = $env:DEVOPS_PAT, + [bool] $IsReleaseBuild = $false +) + +Set-StrictMode -Version 3 +. (Join-Path $PSScriptRoot common.ps1) + +function ProcessPackage($PackageName, $ConfigFileDir) +{ + Write-Host "Artifact path: $($ArtifactPath)" + Write-Host "Package Name: $($PackageName)" + Write-Host "Config File directory: $($ConfigFileDir)" + + &$EngCommonScriptsDir/Validate-Package.ps1 ` + -PackageName $PackageName ` + -ArtifactPath $ArtifactPath ` + -RepoRoot $RepoRoot ` + -APIViewUri $APIViewUri ` + -APIKey $APIKey ` + -BuildDefinition $BuildDefinition ` + -PipelineUrl $PipelineUrl ` + -ConfigFileDir $ConfigFileDir ` + -Devops_pat $Devops_pat + if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to validate package $PackageName" + exit 1 + } +} + +# Check if package config file is present. This file has package version, SDK type etc info. +if (-not $ConfigFileDir) { + $ConfigFileDir = Join-Path -Path $ArtifactPath "PackageInfo" +} +foreach ($artifact in $ArtifactList) +{ + Write-Host "Processing $($artifact.name)" + ProcessPackage -PackageName $artifact.name -ConfigFileDir $ConfigFileDir +} \ No newline at end of file diff --git a/eng/common/scripts/Validate-Package.ps1 b/eng/common/scripts/Validate-Package.ps1 new file mode 100644 index 000000000..57f093d76 --- /dev/null +++ b/eng/common/scripts/Validate-Package.ps1 @@ -0,0 +1,252 @@ +#This script is responsible for release preparedness check that's run as part of build pipeline. + +[CmdletBinding()] +param ( + [Parameter(Mandatory = $true)] + [string] $PackageName, + [Parameter(Mandatory = $true)] + [string] $ArtifactPath, + [Parameter(Mandatory=$True)] + [string] $RepoRoot, + [Parameter(Mandatory=$True)] + [string] $APIKey, + [Parameter(Mandatory=$True)] + [string] $ConfigFileDir, + [string] $BuildDefinition, + [string] $PipelineUrl, + [string] $APIViewUri, + [string] $Devops_pat = $env:DEVOPS_PAT, + [bool] $IsReleaseBuild = $false +) +Set-StrictMode -Version 3 + +. (Join-Path $PSScriptRoot common.ps1) +. ${PSScriptRoot}\Helpers\ApiView-Helpers.ps1 +. ${PSScriptRoot}\Helpers\DevOps-WorkItem-Helpers.ps1 + +if (!$Devops_pat) { + az account show *> $null + if (!$?) { + Write-Host 'Running az login...' + az login *> $null + } +} +else { + # Login using PAT + LoginToAzureDevops $Devops_pat +} + +az extension show -n azure-devops *> $null +if (!$?){ + az extension add --name azure-devops +} else { + # Force update the extension to the latest version if it was already installed + # this is needed to ensure we have the authentication issue fixed from earlier versions + az extension update -n azure-devops *> $null +} + +CheckDevOpsAccess + +# Function to validate change log +function ValidateChangeLog($changeLogPath, $versionString, $validationStatus) +{ + try + { + $ChangeLogStatus = [PSCustomObject]@{ + IsValid = $false + Message = "" + } + $changeLogFullPath = Join-Path $RepoRoot $changeLogPath + Write-Host "Path to change log: [$changeLogFullPath]" + if (Test-Path $changeLogFullPath) + { + Confirm-ChangeLogEntry -ChangeLogLocation $changeLogFullPath -VersionString $versionString -ForRelease $true -ChangeLogStatus $ChangeLogStatus + $validationStatus.Status = if ($ChangeLogStatus.IsValid) { "Success" } else { "Failed" } + $validationStatus.Message = $ChangeLogStatus.Message + } + else { + $validationStatus.Status = "Failed" + $validationStatus.Message = "Change log is not found in [$changeLogPath]. Change log file must be present in package root directory." + } + } + catch + { + Write-Host "Current directory: $(Get-Location)" + $validationStatus.Status = "Failed" + $validationStatus.Message = $_.Exception.Message + } +} + +# Function to verify API review status +function VerifyAPIReview($packageName, $packageVersion, $language) +{ + $APIReviewValidation = [PSCustomObject]@{ + Name = "API Review Approval" + Status = "Pending" + Message = "" + } + $PackageNameValidation = [PSCustomObject]@{ + Name = "Package Name Approval" + Status = "Pending" + Message = "" + } + + try + { + $apiStatus = [PSCustomObject]@{ + IsApproved = $false + Details = "" + } + $packageNameStatus = [PSCustomObject]@{ + IsApproved = $false + Details = "" + } + Write-Host "Checking API review status for package $packageName with version $packageVersion. language [$language]." + Check-ApiReviewStatus $packageName $packageVersion $language $APIViewUri $APIKey $apiStatus $packageNameStatus + + Write-Host "API review approval details: $($apiStatus.Details)" + Write-Host "Package name approval details: $($packageNameStatus.Details)" + #API review approval status + $APIReviewValidation.Message = $apiStatus.Details + $APIReviewValidation.Status = if ($apiStatus.IsApproved) { "Approved" } else { "Pending" } + + # Package name approval status + $PackageNameValidation.Status = if ($packageNameStatus.IsApproved) { "Approved" } else { "Pending" } + $PackageNameValidation.Message = $packageNameStatus.Details + } + catch + { + Write-Warning "Failed to get API review status. Error: $_" + $PackageNameValidation.Status = "Failed" + $PackageNameValidation.Message = $_.Exception.Message + $APIReviewValidation.Status = "Failed" + $APIReviewValidation.Message = $_.Exception.Message + } + + return [PSCustomObject]@{ + ApiviewApproval = $APIReviewValidation + PackageNameApproval = $PackageNameValidation + } +} + + +function IsVersionShipped($packageName, $packageVersion) +{ + # This function will decide if a package version is already shipped or not + Write-Host "Checking if a version is already shipped for package $packageName with version $packageVersion." + $parsedNewVersion = [AzureEngSemanticVersion]::new($packageVersion) + $versionMajorMinor = "" + $parsedNewVersion.Major + "." + $parsedNewVersion.Minor + $workItem = FindPackageWorkItem -lang $LanguageDisplayName -packageName $packageName -version $versionMajorMinor -includeClosed $true -outputCommand $false + if ($workItem) + { + # Check if the package version is already shipped + $shippedVersionSet = ParseVersionSetFromMDField $workItem.fields["Custom.ShippedPackages"] + if ($shippedVersionSet.ContainsKey($packageVersion)) { + return $true + } + } + else { + Write-Host "No work item found for package [$packageName]. Creating new work item for package." + } + return $false +} + +function CreateUpdatePackageWorkItem($pkgInfo) +{ + # This function will create or update package work item in Azure DevOps + $versionString = $pkgInfo.Version + $packageName = $pkgInfo.Name + $plannedDate = $pkgInfo.ReleaseStatus + $setReleaseState = $true + if (!$plannedDate -or $plannedDate -eq "Unreleased") + { + $setReleaseState = $false + $plannedDate = "unknown" + } + + # Create or update package work item + &$EngCommonScriptsDir/Update-DevOps-Release-WorkItem.ps1 ` + -language $LanguageDisplayName ` + -packageName $packageName ` + -version $versionString ` + -plannedDate $plannedDate ` + -packageRepoPath $pkgInfo.serviceDirectory ` + -packageType $pkgInfo.SDKType ` + -packageNewLibrary $pkgInfo.IsNewSDK ` + -serviceName "unknown" ` + -packageDisplayName "unknown" ` + -inRelease $IsReleaseBuild ` + -devops_pat $Devops_pat + + if ($LASTEXITCODE -ne 0) + { + Write-Host "Update of the Devops Release WorkItem failed." + return $false + } + return $true +} + +# Read package property file and identify all packages to process +Write-Host "Processing package: $PackageName" +Write-Host "Is Release Build: $IsReleaseBuild" +$packagePropertyFile = Join-Path $ConfigFileDir "$PackageName.json" +$pkgInfo = Get-Content $packagePropertyFile | ConvertFrom-Json + +$changeLogPath = $pkgInfo.ChangeLogPath +$versionString = $pkgInfo.Version +Write-Host "Checking if we need to create or update work item for package $packageName with version $versionString." +$isShipped = IsVersionShipped $packageName $versionString +if ($isShipped) { + Write-Host "Package work item already exists for version [$versionString] that is marked as shipped. Skipping the update of package work item." + exit 0 +} + +Write-Host "Validating package $packageName with version $versionString." + +# Change log validation +$changeLogStatus = [PSCustomObject]@{ + Name = "Change Log Validation" + Status = "Success" + Message = "" +} +ValidateChangeLog $changeLogPath $versionString $changeLogStatus + +# API review and package name validation +$apireviewDetails = VerifyAPIReview $PackageName $pkgInfo.Version $Language + +$pkgValidationDetails= [PSCustomObject]@{ + Name = $PackageName + Version = $pkgInfo.Version + ChangeLogValidation = $changeLogStatus + APIReviewValidation = $apireviewDetails.ApiviewApproval + PackageNameValidation = $apireviewDetails.PackageNameApproval +} + +$output = ConvertTo-Json $pkgValidationDetails +Write-Host "Output: $($output)" + +# Create json token file in artifact path +$tokenFile = Join-Path $ArtifactPath "$PackageName-Validation.json" +$output | Out-File -FilePath $tokenFile -Encoding utf8 + +# Create DevOps work item +$updatedWi = CreateUpdatePackageWorkItem $pkgInfo + +# Update validation status in package work item +if ($updatedWi) { + Write-Host "Updating validation status in package work item." + $updatedWi = UpdateValidationStatus $pkgValidationDetails $BuildDefinition $PipelineUrl +} + +# Fail the build if any validation is not successful for a release build +Write-Host "Change log status:" $changelogStatus.Status +Write-Host "API Review status:" $apireviewDetails.ApiviewApproval.Status +Write-Host "Package Name status:" $apireviewDetails.PackageNameApproval.Status + +if ($IsReleaseBuild) +{ + if (!$updatedWi -or $changelogStatus.Status -ne "Success" -or $apireviewDetails.ApiviewApproval.Status -ne "Approved" -or $apireviewDetails.PackageNameApproval.Status -ne "Approved") { + Write-Error "At least one of the Validations above failed for package $PackageName with version $versionString." + exit 1 + } +} \ No newline at end of file