Created
November 3, 2024 09:23
-
-
Save tamirs9876/4f5e7db9eb68058ba5bfdaadf9342d65 to your computer and use it in GitHub Desktop.
Exports Azure DevOps Pull Requests and Threads (comments) discussion.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
NOTES: | |
1. This script export *completed* pull requests and their comments while ignoring active/abandon pull requests | |
2. Pull request description is truncated after 400 symbols, as per Azure DevOps API documentation. | |
3. Linked Work Items are not exported. | |
4. The script uses Azure CLI to get the access token. It is also possible to use PAT from Azure DevOps. | |
#> | |
param ( | |
[Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $OrganizationName, | |
[Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $RepositoryName, | |
[Parameter(Mandatory=$false)][ValidateNotNullOrEmpty()] $DumpDir = "dump" | |
) | |
# Stop the script when a cmdlet or a native command fails | |
$ErrorActionPreference = 'Stop' | |
$PSNativeCommandUseErrorActionPreference = $true | |
$ApiVersion = "7.1" | |
$OrgUri = "https://dev.azure.com/${OrganizationName}/" | |
$BearerToken = $(az account get-access-token --query accessToken --output tsv) | |
$AzureDevOpsAuthenicationHeader = @{Authorization = "Bearer ${BearerToken}" } | |
function CallApi($Uri) { | |
for ($i = 0; $i -lt 3; $i++) { | |
try { | |
return (Invoke-RestMethod -Uri $Uri -Method get -Headers $AzureDevOpsAuthenicationHeader).value | |
} | |
catch { | |
if ($i -ge 2) { | |
Write-Output "Failed to call: ${Uri}" | |
Write-Output "Error message: $($_.Exception.Message)" | |
exit 1 | |
} | |
Start-Sleep -Seconds 3 | |
} | |
} | |
} | |
function GetFileNameForPullRequest($Pr) { | |
# Avoid potentially invalid file name characters | |
$Title = $Pr.title -replace "[^a-zA-Z0-9 ]", "." | |
$Id = $Pr.pullRequestId | |
$Date = $Pr.closedDate.ToString("yyyyMMdd") | |
return "${Date}-${Id}-${Title}" | |
} | |
# Get repo Id (required for the next API calls) | |
$GetRepoIdUri = "${OrgUri}_apis/git/repositories/?api-version=${ApiVersion}" | |
$RepositoryId = (CallApi $GetRepoIdUri | Where-Object { $_.name -ieq $RepositoryName })[0].id | |
$Top = 100 | |
$Skip = 0 | |
$Total = 0 | |
while ($true) { | |
# Get completed pull requests | |
$GetPRsUri = "${OrgUri}_apis/git/repositories/${RepositoryId}/pullrequests/?`$top=${Top}&`$skip=${Skip}&searchCriteria.status=completed&api-version=${ApiVersion}" | |
$CompletedPullRequests = CallApi $GetPRsUri | |
if (-not (Test-Path $DumpDir)) { | |
New-Item -ItemType Directory -Path $DumpDir | Out-Null | |
} | |
foreach ($Pr in $CompletedPullRequests) { | |
$PrFileName = GetFileNameForPullRequest $Pr | |
$Pr | ConvertTo-Json -Depth 100 | Out-File -Path "${DumpDir}/${PrFileName}.json" | |
# Get PR comments | |
$GetCommentsUri = "${OrgUri}_apis/git/repositories/${RepositoryId}/pullRequests/$($Pr.pullRequestId)/threads?api-version=${ApiVersion}" | |
$Comments = CallApi $GetCommentsUri | |
$Comments | ConvertTo-Json -Depth 100 | Out-File -Path "${DumpDir}/${PrFileName}-comments.json" | |
} | |
Write-Verbose "Exporting $($CompletedPullRequests.Count) pull requests completed" | |
$Total += $CompletedPullRequests.Count | |
if ($CompletedPullRequests.Count -lt $Top) { | |
# Last batch processed | |
break | |
} | |
else { | |
$Skip += $Top | |
} | |
} | |
Write-Output "Total ${Total} pull requests exported to ${DumpDir}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment