eng/scripts/Update-DevOps-WorkItems.ps1 (332 lines of code) (raw):

[CmdletBinding()] param ( [string] $pkgFilter = $null, [bool] $updateAllVersions = $false, # When false only updates the versions in the preview and ga in csv [string] $github_pat = $env:GITHUB_PAT, [bool] $ignoreReleasePlannerTests = $true ) Set-StrictMode -Version 3 . (Join-Path $PSScriptRoot PackageList-Helpers.ps1) . (Join-Path $PSScriptRoot .. common scripts Helpers DevOps-WorkItem-Helpers.ps1) if (!(Get-Command az -ErrorAction SilentlyContinue)) { Write-Error 'You must have the Azure CLI installed: https://aka.ms/azure-cli' exit 1 } az account show *> $null if (!$?) { Write-Host 'Running az login...' az login *> $null } az extension show -n azure-devops *> $null if (!$?) { Write-Host 'Installing azure-devops extension' 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 } $allVersions = @{} $allPackagesFromCSV = @{} $allLangPkgVersions = @{} function GetVersionGroupForPackage($lang, $pkg) { $versions = @() $langPkgVersions = $allLangPkgVersions[$lang] # Consider adding the versions from the csv but we don't have a date for them currently if ($langPkgVersions.ContainsKey($pkg.Package)) { $versions += $langPkgVersions[$pkg.Package].Versions } if ($pkg.VersionGA -and ($versions.Count -eq 0 -or $versions.RawVersion -notcontains $pkg.VersionGA)) { $versions += ToSemVer $pkg.VersionGA } if ($pkg.VersionPreview -and ($versions.Count -eq 0 -or $versions.RawVersion -notcontains $pkg.VersionPreview)) { $versions += ToSemVer $pkg.VersionPreview } $versions = @([AzureEngSemanticVersion]::SortVersions($versions)) if ($versions.Count -eq 0) { Write-Verbose "No versioning information for $lang - $($pkg.Package)" continue } $verGroups = $versions | Group-Object -Property Major, Minor return $verGroups } function InitializeVersionInformation() { if ($allVersions.Count -gt 0) { return } foreach ($lang in $languageNameMapping.Keys) { $langName = Get-LanguageName $lang $packageList = Get-PackageListForLanguage $lang $allPackagesFromCSV[$langName] = $packageList $packageList, $_ = Get-PackageListSplit $packageList if ($pkgFilter) { $packageList = $packageList | Where-Object { $_.Package -like $pkgFilter } } $allLangPkgVersions[$langName] = GetPackageVersions $lang Write-Verbose "Found $($allLangPkgVersions[$langName].Count) versions for language $langName" $packageSet = @{} foreach ($pkg in $packageList) { $verGroups = GetVersionGroupForPackage $langName $pkg $pkgVerGroups = @{} foreach ($verGroup in $verGroups) { $verMajMin = ($verGroup.Name -replace ", ", ".") if (!$updateAllVersions) { if (!(PackageMatchesVersionGroup $pkg $verMajMin)) { continue } } $pkgVerGroups[$verMajMin] = New-Object PSObject -Property @{ Versions = $verGroup.Group VersionMajorMinor = $verMajMin PackageInfo = $pkg } } $packageSet[$pkg.Package] = New-Object PSObject -Property @{ VersionGroups = $pkgVerGroups PackageInfo = $pkg } } $allVersions[$langName] = $packageSet } } function GetVersionInfo($pkgLang, $pkgName, $verMajorMinor) { InitializeVersionInformation if (!$allVersions.ContainsKey($pkgLang)) { return $null } if (!$allVersions[$pkgLang].ContainsKey($pkgName)) { return $null } # Return the package item if the version isn't passed if (!$verMajorMinor){ return $allVersions[$pkgLang][$pkgName] } if (!$allVersions[$pkgLang][$pkgName].VersionGroups.ContainsKey($verMajorMinor)) { return $null } return $allVersions[$pkgLang][$pkgName].VesionGroups[$verMajorMinor] } function PackageMatchesVersionGroup($pkg, $versionGroupToCheck) { if ($pkg.VersionGA -and $pkg.VersionGA.StartsWith($versionGroupToCheck)) { return $true } if ($pkg.VersionPreview -and $pkg.VersionPreview.StartsWith($versionGroupToCheck)) { return $true } return $false } function ParseVersionsFromTags($versionsFromTags, $existingShippedVersionSet) { $versionList = @() foreach ($v in $versionsFromTags) { $d = "Unknown" if ($existingShippedVersionSet.ContainsKey($v.RawVersion)) { # Use cached values from the work items $d = $existingShippedVersionSet[$v.RawVersion].Date } # if we don't have a cached value or the cached value is Unknown look at the # release tag to try and get a date if we have one $tagDate = $v.Date -as [DateTime] if ($d -eq "Unknown" -and $tagDate) { $d = $tagDate.ToString("MM/dd/yyyy") } $versionList += New-Object PSObject -Property @{ Type = $v.VersionType Version = $v.RawVersion Date = $d } } return ,$versionList } function UpdateShippedPackageVersions($pkgWorkItem, $versionsFromTags) { $existingVersions = ParseVersionSetFromMDField $pkgWorkItem.fields["Custom.ShippedPackages"] $shippedVersions = ParseVersionsFromTags $versionsFromTags $existingVersions return UpdatePackageVersions $pkgWorkItem -shippedVersions $shippedVersions } function RefreshItems() { InitializeVersionInformation InitializeWorkItemCache $allPackageWorkItems = GetCachedPackageWorkItems if ($pkgFilter) { $allPackageWorkItems = $allPackageWorkItems | Where-Object { $_.fields["Custom.Package"] -like $pkgFilter } } $allVersionValues = @{} ## Loop over all package work items foreach ($pkgWI in $allPackageWorkItems) { $pkgLang = $pkgWI.fields["Custom.Language"] $pkgName = $pkgWI.fields["Custom.Package"] $version = $pkgWI.fields["Custom.PackageVersionMajorMinor"] if (!$pkgLang -or !$pkgName -or !$version) { Write-Warning "Skipping item $($pkgWI.id) because it doesn't have one or all of the required language, package, or version fields." continue } if ($version -match "(?<major>\d+)\.(?<minor>\d+)") { $verMajorMinor = "" + $matches["major"] + "." + $matches["minor"] } else { Write-Warning "Version for item $($pkgWI.id) is set to [$version] which is not a valid version. Skipping" continue } # Get version info, note this only gets the packages with New=True in this case. $pkgInfo = GetVersionInfo $pkgLang $pkgName $pkg = $null $versions = $null # If the csv entry is marked as "Needs Review" we want to prefer the data in the workitem over the data in csv if ($pkgInfo -and $pkgInfo.PackageInfo.Notes -ne "Needs Review") { if ($pkgInfo.VersionGroups.ContainsKey($verMajorMinor)) { $versions = $pkgInfo.VersionGroups[$verMajorMinor].Versions } $pkg = $pkgInfo.PackageInfo } else { $pkgFromCsv = $allPackagesFromCSV[$pkgLang].Where({ $pkgName -eq $_.Package }) # For java filter down to com.azure* groupId if ($pkgLang -eq "Java") { $pkgFromCsv = $pkgFromCsv.Where({ $_.GroupId -like "com.azure*" }) } if ($pkgFromCsv.Count -ne 0) { if ($pkgFromCsv.Count -gt 1) { Write-Warning "[$($pkgWI.id)]$pkgLang - $pkgName($verMajorMinor) - Detected new package with multiple matching package names in the csv, so skipping it." continue } else { $csvEntry = $pkgFromCsv[0] if ($csvEntry.Hide -eq "true") { # For any entry that is explicitly marked as hidden we should skip any udpating continue } $csvEntryVersion = $csvEntry.VersionGA if (!$csvEntryVersion) { $csvEntryVersion = $csvEntry.VersionPreview } if (!$csvEntryVersion.StartsWith($verMajorMinor)) { Write-Warning "[$($pkgWI.id)]$pkgLang - $pkgName($verMajorMinor) - Detected package work item with different version('$csvEntryVersion') then in CSV, so skipping it." continue } $csvEntry.New = $pkgWI.fields["Custom.PackageTypeNewLibrary"].ToString().ToLower() $csvEntry.Type = $pkgWI.fields["Custom.PackageType"] if ($csvEntry.DisplayName.Contains("Unknown")) { $csvEntry.DisplayName = $pkgWI.fields["Custom.PackageDisplayName"] } if ($csvEntry.ServiceName.Contains("Unknown")) { $csvEntry.ServiceName = $pkgWI.fields["Custom.ServiceName"] } if ($pkgWI.fields["Custom.PackageRepoPath"] -and (!$csvEntry.RepoPath -or "NA" -eq $csvEntry.RepoPath)) { # @azure-rest packages have unique repo path formatting so we need create a custom template for them if ($csvEntry.Package.StartsWith("@azure-rest") -and !$pkgWI.fields["Custom.PackageRepoPath"].StartsWith("https")) { $jsLinkTemplates = GetLinkTemplates "js" $repoPath = $jsLinkTemplates["source_url_template"] # this assumes that the previous PackageRepoPath is the service directory which is generally the case when first created $repoPath = $repoPath -replace "item.RepoPath", $pkgWI.fields["Custom.PackageRepoPath"] # this assumes that the item.TrimmedPackage parameter in the template needs to be remove the scope and add "-rest" to end $repoPath = $repoPath -replace "item.TrimmedPackage", ($csvEntry.Package -replace "@azure-rest/(.*)", "`$1-rest") $csvEntry.RepoPath = $repoPath } else { $csvEntry.RepoPath = $pkgWI.fields["Custom.PackageRepoPath"] } } if (!$csvEntry.RepoPath) { $csvEntry.RepoPath = "NA" } Write-Host "[$($pkgWI.id)]$pkgLang - $pkgName($verMajorMinor) - Detected new package in CSV with a release work item so updating metadata for it in the CSV to match release work item." $verGroups = GetVersionGroupForPackage $pkgLang $csvEntry if ($verGroups) { foreach ($verGroup in $verGroups) { if ($verGroup.Name.Replace(", ", ".") -eq $verMajorMinor) { $versions = $verGroup.Group break; } } } $pkg = $csvEntry } } else { Write-Host "[$($pkgWI.id)]$pkgLang - $pkgName($verMajorMinor) - Detected new package not in CSV file. Only normalizing release work item until release." $pkg = [PSCustomObject][ordered]@{ Package = $pkgName DisplayName = $pkgWI.fields["Custom.PackageDisplayName"] ServiceName = $pkgWI.fields["Custom.ServiceName"] RepoPath = $pkgWI.fields["Custom.PackageRepoPath"] Type = $pkgWI.fields["Custom.PackageType"] New = $pkgWI.fields["Custom.PackageTypeNewLibrary"].ToString().ToLower() }; } } Write-Verbose "[$($pkgWI.id)]$pkgLang - $pkgName ($verMajorMinor) - '$($pkgWI.fields['System.State'])'" $updatedWI = CreateOrUpdatePackageWorkItem (Get-LanguageName $pkgLang) $pkg $verMajorMinor $pkgWI $updatedWI = UpdateShippedPackageVersions $updatedWI $versions # Collect all the versions if (!$allVersionValues.ContainsKey($pkgLang)) { $allVersionValues[$pkgLang] = @{} } $allVersionValues[$pkgLang][$pkgName] += $($updatedWI.fields["Custom.PackageBetaVersions"]) + "|" $allVersionValues[$pkgLang][$pkgName] += $($updatedWI.fields["Custom.PackageGAVersion"]) + "|" $allVersionValues[$pkgLang][$pkgName] += $($updatedWI.fields["Custom.PackagePatchVersions"]) + "|" } ## Loop over all packages marked as New in CSV files foreach ($pkgLang in $allVersions.Keys) { foreach ($pkgName in $allVersions[$pkgLang].Keys) { foreach ($verMajorMinor in $allVersions[$pkgLang][$pkgName].VersionGroups.Keys) { $verInfo = $allVersions[$pkgLang][$pkgName].VersionGroups[$verMajorMinor] if (!$verInfo.PackageInfo.ServiceName) { Write-Warning "No ServiceName for '$pkgLang - $pkgName' in CSV so not creating a package work-item for it." continue } if (!$verInfo.PackageInfo.DisplayName) { Write-Warning "No DisplayName for '$pkgLang - $pkgName' in CSV so not creating a package work-item for it." continue } if (!$verInfo.PackageInfo.RepoPath -and $verInfo.PackageInfo.RepoPath -eq "NA") { Write-Warning "No RepoPath set for '$pkgLang - $pkgName' in CSV so not creating a package work-item for it." continue } $pkgWI = FindOrCreateClonePackageWorkItem (Get-LanguageName $pkgLang) $verInfo.PackageInfo $verMajorMinor -outputCommand $false Write-Verbose "[$($pkgWI.id)]$pkgLang - $pkgName ($verMajorMinor)" $pkgWI = UpdateShippedPackageVersions $pkgWI $verInfo.Versions } $csvEntry = $allVersions[$pkgLang][$pkgName].PackageInfo if ($csvEntry.PSObject.Members.Name -contains "PlannedVersions" -and $allVersionValues.ContainsKey($pkgLang) -and $allVersionValues[$pkgLang].ContainsKey($pkgName)) { $pkgVersionValues = $allVersionValues[$pkgLang][$pkgName].Split("|").Trim().Where({ $_ }) $pkgPlannedVersions = @{} $today = [DateTime](Get-Date -Format "MM/dd/yyyy") foreach ($pkgVersionValue in $pkgVersionValues) { $ver, $date = $pkgVersionValue.Split(",") if (($date -as [DateTime]) -ge $today) { $pkgPlannedVersions[$ver] = New-Object PSObject -Property @{ Version = $ver Date = ([DateTime]$date).Tostring("MM/dd/yyyy") } } }, $sortedPlannedVersions = $pkgPlannedVersions.Values | Sort-Object @{Expression = {$_.Date -as [DateTime]}; Descending = $false}, Version -Descending | ForEach-Object { "$($_.Version),$($_.Date)" } $csvEntry.PlannedVersions = $sortedPlannedVersions -join "|" } } Set-PackageListForLanguage $pkgLang $allPackagesFromCSV[$pkgLang] } } RefreshItems