# PowerShell script to analyze renovate PRs across repositories with detailed statistics param( [Parameter(Mandatory=$false)] [string]$Organization = "effectory", [Parameter(Mandatory=$false)] [string]$Project = "Survey Software", [Parameter(Mandatory=$true)] [string]$PAT, [Parameter(Mandatory=$false)] [string]$OutputFile = "RenovatePRs_Stats_$(Get-Date -Format 'yyyyMMdd_HHmmss').txt" ) function Write-Output-Both { param ( [string]$Message, [string]$ForegroundColor = "White", [switch]$ConsoleOnly ) Write-Host $Message -ForegroundColor $ForegroundColor if (-not $ConsoleOnly) { Add-Content -Path $OutputFile -Value $Message } } Set-Content -Path $OutputFile -Value "Renovate Pull Requests Statistics - $(Get-Date)`n" $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$PAT")) $headers = @{ Authorization = "Basic $base64AuthInfo" } $reposUrl = "https://dev.azure.com/$Organization/$Project/_apis/git/repositories?api-version=6.0" $repositories = Invoke-RestMethod -Uri $reposUrl -Method Get -Headers $headers $repoStats = @() $reposWithoutRenovate = @() $disabledRepos = @() foreach ($repo in $repositories.value) { $repoName = $repo.name $repoId = $repo.id Write-Output-Both "Analyzing repository: $repoName" -ForegroundColor Gray -ConsoleOnly $isDisabled = $repo.isDisabled -eq $true $repoDetailsUrl = "https://dev.azure.com/$Organization/$Project/_apis/git/repositories/$repoId`?api-version=6.0" try { $repoDetails = Invoke-RestMethod -Uri $repoDetailsUrl -Method Get -Headers $headers $isLocked = $repoDetails.isLocked -eq $true } catch { Write-Output-Both " Could not retrieve repository details. Assuming not locked." -ForegroundColor Yellow -ConsoleOnly $isLocked = $false } if ($isDisabled -or $isLocked) { $status = if ($isDisabled) { "DISABLED" } elseif ($isLocked) { "LOCKED" } else { "UNKNOWN" } Write-Output-Both " Repository status: $status - Skipping analysis" -ForegroundColor Yellow -ConsoleOnly $disabledRepo = [PSCustomObject]@{ Repository = "$repoName ($status)" TotalRenovatePRs = "N/A" OpenPRs = "N/A" CompletedPRs = "N/A" AbandonedPRs = "N/A" LastCreatedDate = "N/A" LastCompletedDate = "N/A" LatestOpenBranch = "N/A" LatestCompletedBranch = "N/A" LastCompletedPRTitle = "N/A" RepoStatus = $status } $disabledRepos += $disabledRepo continue } $prsUrl = "https://dev.azure.com/$Organization/$Project/_apis/git/repositories/$repoId/pullrequests`?api-version=6.0&searchCriteria.status=all" try { $pullRequests = Invoke-RestMethod -Uri $prsUrl -Method Get -Headers $headers $renovatePRs = $pullRequests.value | Where-Object { $_.sourceRefName -like "refs/heads/renovate/*" } if ($renovatePRs.Count -gt 0) { $openPRs = $renovatePRs | Where-Object { $_.status -eq "active" } $completedPRs = $renovatePRs | Where-Object { $_.status -eq "completed" } $abandonedPRs = $renovatePRs | Where-Object { $_.status -eq "abandoned" } $openCount = $openPRs.Count $completedCount = $completedPRs.Count $abandonedCount = $abandonedPRs.Count $latestOpen = $openPRs | Sort-Object creationDate -Descending | Select-Object -First 1 $latestCompleted = $completedPRs | Sort-Object closedDate -Descending | Select-Object -First 1 $latestCreated = $renovatePRs | Sort-Object creationDate -Descending | Select-Object -First 1 $lastCreatedDate = if ($latestCreated) { $latestCreated.creationDate } else { "N/A" } $lastCompletedDate = if ($latestCompleted) { $latestCompleted.closedDate } else { "N/A" } $lastCompletedPRTitle = if ($latestCompleted) { $latestCompleted.title } else { "N/A" } $latestOpenBranch = if ($latestOpen) { ($latestOpen.sourceRefName -replace "refs/heads/", "") } else { "N/A" } $latestCompletedBranch = if ($latestCompleted) { ($latestCompleted.sourceRefName -replace "refs/heads/", "") } else { "N/A" } $repoStat = [PSCustomObject]@{ Repository = $repoName TotalRenovatePRs = $renovatePRs.Count OpenPRs = $openCount CompletedPRs = $completedCount AbandonedPRs = $abandonedCount LastCreatedDate = $lastCreatedDate LastCompletedDate = $lastCompletedDate LatestOpenBranch = $latestOpenBranch LatestCompletedBranch = $latestCompletedBranch LastCompletedPRTitle = $lastCompletedPRTitle RepoStatus = "ACTIVE" SortDate = if ($lastCreatedDate -eq "N/A") { [DateTime]::MinValue } else { [DateTime]::Parse($lastCreatedDate) } } $repoStats += $repoStat } else { $reposWithoutRenovate += $repoName $repoStat = [PSCustomObject]@{ Repository = $repoName TotalRenovatePRs = 0 OpenPRs = 0 CompletedPRs = 0 AbandonedPRs = 0 LastCreatedDate = "N/A" LastCompletedDate = "N/A" LatestOpenBranch = "N/A" LatestCompletedBranch = "N/A" LastCompletedPRTitle = "N/A" RepoStatus = "ACTIVE" SortDate = [DateTime]::MinValue } $repoStats += $repoStat } } catch { Write-Output-Both " Error accessing pull requests for repository: $_" -ForegroundColor Red -ConsoleOnly $disabledRepo = [PSCustomObject]@{ Repository = "$repoName (ERROR)" TotalRenovatePRs = "Error" OpenPRs = "Error" CompletedPRs = "Error" AbandonedPRs = "Error" LastCreatedDate = "Error" LastCompletedDate = "Error" LatestOpenBranch = "Error" LatestCompletedBranch = "Error" LastCompletedPRTitle = "Error" RepoStatus = "ERROR" } $disabledRepos += $disabledRepo } } Write-Output-Both "`n===== RENOVATE PULL REQUEST STATISTICS BY REPOSITORY (SORTED BY LAST CREATED DATE) =====" -ForegroundColor Green if ($repoStats.Count -gt 0) { $sortedStats = $repoStats | Sort-Object -Property SortDate -Descending $displayStats = $sortedStats | Select-Object Repository, TotalRenovatePRs, OpenPRs, CompletedPRs, AbandonedPRs, @{Name="LastCreated"; Expression={ if ($_.LastCreatedDate -eq "N/A" -or $_.LastCreatedDate -eq "Error") { $_.LastCreatedDate } else { [DateTime]::Parse($_.LastCreatedDate).ToString("yyyy-MM-dd") } }}, @{Name="LastCompleted"; Expression={ if ($_.LastCompletedDate -eq "N/A" -or $_.LastCompletedDate -eq "Error") { $_.LastCompletedDate } else { [DateTime]::Parse($_.LastCompletedDate).ToString("yyyy-MM-dd") } }}, LatestOpenBranch, LatestCompletedBranch, LastCompletedPRTitle $displayStats | Export-Csv -Path "$($OutputFile).csv" -NoTypeInformation # Add a note to the original output file Add-Content -Path $OutputFile -Value "Full data available in: $($OutputFile).csv" $statsTable = $displayStats | Format-Table -Property Repository, TotalRenovatePRs, OpenPRs, CompletedPRs, AbandonedPRs, LastCreated, LastCompleted, LatestCompletedBranch, LastCompletedPRTitle | Out-String Add-Content -Path $OutputFile -Value $statsTable.Trim() # Trim to remove extra whitespace $displayStats | Format-Table -AutoSize $totalRepos = $repositories.value.Count $reposWithRenovate = ($repoStats | Where-Object { $_.TotalRenovatePRs -gt 0 }).Count $reposDisabledOrLocked = $disabledRepos.Count $activeRepos = $totalRepos - $reposDisabledOrLocked $percentWithRenovate = if ($activeRepos -gt 0) { [math]::Round(($reposWithRenovate / $activeRepos) * 100, 2) } else { 0 } $totalPRs = ($repoStats | Measure-Object -Property TotalRenovatePRs -Sum).Sum $totalOpenPRs = ($repoStats | Measure-Object -Property OpenPRs -Sum).Sum $totalCompletedPRs = ($repoStats | Measure-Object -Property CompletedPRs -Sum).Sum $totalAbandonedPRs = ($repoStats | Measure-Object -Property AbandonedPRs -Sum).Sum Write-Output-Both "`n===== SUMMARY STATISTICS =====" -ForegroundColor Cyan Write-Output-Both "Total repositories: $totalRepos" Write-Output-Both "Disabled, locked, or error repositories: $reposDisabledOrLocked" Write-Output-Both "Active repositories: $activeRepos" Write-Output-Both "Active repositories with renovate PRs: $reposWithRenovate ($percentWithRenovate%)" Write-Output-Both "Active repositories without renovate PRs: $($activeRepos - $reposWithRenovate) ($(100 - $percentWithRenovate)%)" Write-Output-Both "`nTotal renovate PRs: $totalPRs" Write-Output-Both "Total open renovate PRs: $totalOpenPRs" Write-Output-Both "Total completed renovate PRs: $totalCompletedPRs" Write-Output-Both "Total abandoned renovate PRs: $totalAbandonedPRs" if ($disabledRepos.Count -gt 0) { Write-Output-Both "`n===== DISABLED/LOCKED/ERROR REPOSITORIES (NOT INCLUDED IN MAIN REPORT) =====" -ForegroundColor Yellow $disabledList = $disabledRepos | ForEach-Object { $_.Repository } Write-Output-Both ($disabledList -join "`n") } } else { Write-Output-Both "No active repositories found." -ForegroundColor Yellow } Write-Output-Both "`nReport saved to: $OutputFile" -ForegroundColor Cyan