Skip to content

Commit bbd295a

Browse files
Update devops workitem helpers (Azure#16083)
- Switch to using rest instead of cli for querying work items as cli is limited to 1000 items only. - Fix issues with Generated fields not being set. - Correctly sort older workitems by version isntead of string. Co-authored-by: Wes Haggard <Wes.Haggard@microsoft.com>
1 parent 702007a commit bbd295a

File tree

1 file changed

+105
-36
lines changed

1 file changed

+105
-36
lines changed

eng/common/scripts/Helpers/DevOps-WorkItem-Helpers.ps1

Lines changed: 105 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,77 @@ function Invoke-AzBoardsCmd($subCmd, $parameters, $output = $true)
1212
return Invoke-Expression "$azCmdStr" | ConvertFrom-Json -AsHashTable
1313
}
1414

15+
function Invoke-Query($fields, $wiql, $output = $true)
16+
{
17+
#POST https://dev.azure.com/{organization}/{project}/{team}/_apis/wit/wiql?timePrecision={timePrecision}&$top={$top}&api-version=6.1-preview.2
18+
19+
$body = @"
20+
{
21+
"query": "$wiql"
22+
}
23+
"@
24+
25+
if ($output) {
26+
Write-Host "Executing query $wiql"
27+
}
28+
29+
$headers = $null
30+
if (Get-Variable -Name "devops_pat" -ValueOnly -ErrorAction "Ignore")
31+
{
32+
$encodedToken = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes([string]::Format("{0}:{1}", "", $devops_pat)))
33+
$headers = @{ Authorization = "Basic $encodedToken" }
34+
}
35+
else
36+
{
37+
# Get a temp access token from the logged in az cli user for azure devops resource
38+
$jwt_accessToken = (az account get-access-token --resource "499b84ac-1321-427f-aa17-267ca6975798" --query "accessToken" --output tsv)
39+
$headers = @{ Authorization = "Bearer $jwt_accessToken" }
40+
}
41+
$response = Invoke-RestMethod -Method POST `
42+
-Uri "https://dev.azure.com/azure-sdk/Release/_apis/wit/wiql/?`$top=10000&api-version=6.0" `
43+
-Headers $headers -Body $body -ContentType "application/json" | ConvertTo-Json -Depth 10 | ConvertFrom-Json -AsHashTable
44+
45+
if (!$response.workItems) {
46+
Write-Verbose "Query returned no items. $wiql"
47+
return ,@()
48+
}
49+
50+
$workItems = @()
51+
$i = 0
52+
do
53+
{
54+
$idBatch = @()
55+
while ($idBatch.Count -lt 200 -and $i -lt $response.workItems.Count)
56+
{
57+
$idBatch += $response.workItems[$i].id
58+
$i++
59+
}
60+
61+
$uri = "https://dev.azure.com/azure-sdk/Release/_apis/wit/workitems?ids=$($idBatch -join ',')&fields=$($fields -join ',')&api-version=6.0"
62+
63+
Write-Verbose "Pulling work items $uri "
64+
65+
$batchResponse = Invoke-RestMethod -Method GET -Uri $uri `
66+
-Headers $headers -ContentType "application/json" -MaximumRetryCount 3 | ConvertTo-Json -Depth 10 | ConvertFrom-Json -AsHashTable
67+
68+
if ($batchResponse.value)
69+
{
70+
$batchResponse.value | % { $workItems += $_ }
71+
}
72+
else
73+
{
74+
Write-Warning "Batch return no items from $uri"
75+
}
76+
}
77+
while ($i -lt $response.workItems.Count)
78+
79+
if ($output) {
80+
Write-Host "Query return $($workItems.Count) items"
81+
}
82+
83+
return $workItems
84+
}
85+
1586
function LoginToAzureDevops([string]$devops_pat)
1687
{
1788
if (!$devops_pat) {
@@ -64,13 +135,14 @@ function FindParentWorkItem($serviceName, $packageDisplayName, $outputCommand =
64135
$serviceCondition = "[ServiceName] <> ''"
65136
}
66137

67-
$parameters = $ReleaseDevOpsCommonParametersWithProject
68-
$parameters += "--wiql"
69-
$parameters += "`"SELECT [ID], [ServiceName], [PackageDisplayName], [Parent] FROM WorkItems WHERE [Work Item Type] = 'Epic' AND ${serviceCondition}`""
138+
$query = "SELECT [ID], [ServiceName], [PackageDisplayName], [Parent] FROM WorkItems WHERE [Work Item Type] = 'Epic' AND ${serviceCondition}"
70139

71-
$workItems = Invoke-AzBoardsCmd "query" $parameters $outputCommand
140+
$fields = @("System.Id", "Custom.ServiceName", "Custom.PackageDisplayName", "System.Parent")
72141

73-
foreach ($wi in $workItems) {
142+
$workItems = Invoke-Query $fields $query $outputCommand
143+
144+
foreach ($wi in $workItems)
145+
{
74146
$localKey = BuildHashKey $wi.fields["Custom.ServiceName"] $wi.fields["Custom.PackageDisplayName"]
75147
if (!$localKey) { continue }
76148
if ($parentWorkItems.ContainsKey($localKey) -and $parentWorkItems[$localKey].id -ne $wi.id) {
@@ -107,9 +179,7 @@ function FindLatestPackageWorkItem($lang, $packageName, $outputCommand = $true)
107179
continue
108180
}
109181

110-
# Note this only does string sorting which is enough for our current usages
111-
# if we need absolute sorting at some point we would need to parse these versions
112-
if ($wi.fields["Custom.PackageVersionMajorMinor"] -gt $latestWI.fields["Custom.PackageVersionMajorMinor"]) {
182+
if (($wi.fields["Custom.PackageVersionMajorMinor"] -as [Version]) -gt ($latestWI.fields["Custom.PackageVersionMajorMinor"] -as [Version])) {
113183
$latestWI = $wi
114184
}
115185
}
@@ -124,26 +194,26 @@ function FindPackageWorkItem($lang, $packageName, $version, $outputCommand = $tr
124194
}
125195

126196
$fields = @()
127-
$fields += "ID"
128-
$fields += "State"
197+
$fields += "System.ID"
198+
$fields += "System.State"
129199
$fields += "System.AssignedTo"
130-
$fields += "Parent"
131-
$fields += "Language"
132-
$fields += "Package"
133-
$fields += "PackageDisplayName"
134-
$fields += "Title"
135-
$fields += "PackageType"
136-
$fields += "PackageTypeNewLibrary"
137-
$fields += "PackageVersionMajorMinor"
138-
$fields += "PackageRepoPath"
139-
$fields += "ServiceName"
140-
$fields += "Planned Packages"
141-
$fields += "Shipped Packages"
142-
$fields += "PackageBetaVersions"
143-
$fields += "PackageGAVersion"
144-
$fields += "PackagePatchVersions"
145-
$fields += "Generated"
146-
$fields += "RoadmapState"
200+
$fields += "System.Parent"
201+
$fields += "Custom.Language"
202+
$fields += "Custom.Package"
203+
$fields += "Custom.PackageDisplayName"
204+
$fields += "System.Title"
205+
$fields += "Custom.PackageType"
206+
$fields += "Custom.PackageTypeNewLibrary"
207+
$fields += "Custom.PackageVersionMajorMinor"
208+
$fields += "Custom.PackageRepoPath"
209+
$fields += "Custom.ServiceName"
210+
$fields += "Custom.PlannedPackages"
211+
$fields += "Custom.ShippedPackages"
212+
$fields += "Custom.PackageBetaVersions"
213+
$fields += "Custom.PackageGAVersion"
214+
$fields += "Custom.PackagePatchVersions"
215+
$fields += "Custom.Generated"
216+
$fields += "Custom.RoadmapState"
147217

148218
$fieldList = ($fields | ForEach-Object { "[$_]"}) -join ", "
149219
$query = "SELECT ${fieldList} FROM WorkItems WHERE [Work Item Type] = 'Package'"
@@ -160,14 +230,8 @@ function FindPackageWorkItem($lang, $packageName, $version, $outputCommand = $tr
160230
if ($version) {
161231
$query += " AND [PackageVersionMajorMinor] = '${version}'"
162232
}
163-
$parameters = $ReleaseDevOpsCommonParametersWithProject
164-
$parameters += "--wiql", "`"${query}`""
165-
166-
$workItems = Invoke-AzBoardsCmd "query" $parameters $outputCommand
167233

168-
if ($workItems -and $workItems.Count -eq 1000) {
169-
Write-Warning "Retrieved the max of 1000 items so item list might not be complete."
170-
}
234+
$workItems = Invoke-Query $fields $query $outputCommand
171235

172236
foreach ($wi in $workItems)
173237
{
@@ -316,8 +380,13 @@ function FindOrCreateClonePackageWorkItem($lang, $pkg, $verMajorMinor, $allowPro
316380
$pkg.RepoPath = $pkg.fields["Custom.PackageRepoPath"]
317381
}
318382

319-
$extraFields += "`"Generated=" + $latestVersionItem.fields["Custom.Generated"] + "`""
320-
$extraFields += "`"RoadmapState=" + $latestVersionItem.fields["Custom.RoadmapState"] + "`""
383+
if ($latestVersionItem.fields["Custom.Generated"]) {
384+
$extraFields += "`"Generated=" + $latestVersionItem.fields["Custom.Generated"] + "`""
385+
}
386+
387+
if ($latestVersionItem.fields["Custom.RoadmapState"]) {
388+
$extraFields += "`"RoadmapState=" + $latestVersionItem.fields["Custom.RoadmapState"] + "`""
389+
}
321390
}
322391

323392
if ($allowPrompt) {

0 commit comments

Comments
 (0)