mirror of https://github.com/microsoft/vcpkg.git
[scripts] Script to close inactive pull requests and a comment template (#52417)
Co-authored-by: Billy Robert O'Neal III <bion@microsoft.com>
This commit is contained in:
parent
e9f78231ca
commit
bf9b41d24a
|
|
@ -0,0 +1,3 @@
|
|||
We have [closed this PR due to inactivity](https://learn.microsoft.com/vcpkg/contributing/maintainer-guide#close-inactive-prs). Please create a new PR if you're still interested in getting these changes merged.
|
||||
|
||||
This action was performed automatically.
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
#Requires -Version 7.0
|
||||
|
||||
param(
|
||||
[ValidateRange(1, [int]::MaxValue)]
|
||||
[int]$Age = 120,
|
||||
|
||||
[string]$Repo = 'microsoft/vcpkg',
|
||||
|
||||
[ValidateRange(1, [int]::MaxValue)]
|
||||
[int]$Limit = 1000,
|
||||
|
||||
[string]$OutputFile,
|
||||
|
||||
[ValidateScript({
|
||||
if ($_ -and -not (Test-Path -LiteralPath $_ -PathType Leaf)) {
|
||||
throw '-CloseWithComment requires a valid markdown file path.'
|
||||
}
|
||||
|
||||
$true
|
||||
})]
|
||||
[string]$CloseWithComment
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$NoStaleLabel = 'no-stale'
|
||||
|
||||
function Invoke-GhCommand {
|
||||
param([Parameter(Mandatory)][string[]]$Arguments)
|
||||
|
||||
$previousGhToken = $env:GH_TOKEN
|
||||
$previousGithubToken = $env:GITHUB_TOKEN
|
||||
|
||||
Remove-Item Env:GH_TOKEN -ErrorAction SilentlyContinue
|
||||
Remove-Item Env:GITHUB_TOKEN -ErrorAction SilentlyContinue
|
||||
|
||||
try {
|
||||
$output = & gh @Arguments 2>&1
|
||||
return @{ Output = $output; ExitCode = $LASTEXITCODE }
|
||||
}
|
||||
finally {
|
||||
if ($null -eq $previousGhToken) {
|
||||
Remove-Item Env:GH_TOKEN -ErrorAction SilentlyContinue
|
||||
}
|
||||
else {
|
||||
$env:GH_TOKEN = $previousGhToken
|
||||
}
|
||||
|
||||
if ($null -eq $previousGithubToken) {
|
||||
Remove-Item Env:GITHUB_TOKEN -ErrorAction SilentlyContinue
|
||||
}
|
||||
else {
|
||||
$env:GITHUB_TOKEN = $previousGithubToken
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Get-GhPrList {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string]$Repo,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[int]$Limit,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[string]$CutoffDate
|
||||
)
|
||||
|
||||
$searchQuery = "is:pr updated:<$CutoffDate -label:$NoStaleLabel sort:updated-asc"
|
||||
$command = @('pr', 'list', '--repo', $Repo, '--state', 'open', '--limit', $Limit.ToString(), '--search', $searchQuery, '--json', 'number,title,url,updatedAt,labels,author')
|
||||
$result = Invoke-GhCommand -Arguments $command
|
||||
|
||||
if ($result.ExitCode -ne 0) {
|
||||
$message = ($result.Output | Out-String).Trim()
|
||||
throw "Unable to list PRs with gh: $message"
|
||||
}
|
||||
|
||||
return ($result.Output | Out-String) | ConvertFrom-Json -AsHashtable
|
||||
}
|
||||
|
||||
function Get-AgeDays {
|
||||
param([Parameter(Mandatory)][string]$UpdatedAt)
|
||||
|
||||
$updatedUtc = [datetime]::Parse(
|
||||
$UpdatedAt,
|
||||
[System.Globalization.CultureInfo]::InvariantCulture,
|
||||
[System.Globalization.DateTimeStyles]::AssumeUniversal -bor [System.Globalization.DateTimeStyles]::AdjustToUniversal
|
||||
)
|
||||
|
||||
return [int][Math]::Floor(((Get-Date).ToUniversalTime() - $updatedUtc).TotalDays)
|
||||
}
|
||||
|
||||
function Write-CandidateReport {
|
||||
param(
|
||||
[Parameter(Mandatory)][hashtable]$Pr,
|
||||
[Parameter(Mandatory)][int]$AgeDays
|
||||
)
|
||||
|
||||
$labels = @($Pr.labels | ForEach-Object { $_.name })
|
||||
$labelText = if ($labels.Count -gt 0) { ($labels | Sort-Object -Unique) -join ', ' } else { '(none)' }
|
||||
$age = Get-AgeDays -UpdatedAt $Pr.updatedAt
|
||||
$authorObject = $Pr['author']
|
||||
$author = if ($authorObject -and $authorObject.Contains('login')) { [string]$authorObject['login'] } else { '(unknown)' }
|
||||
|
||||
return @(
|
||||
"PR #$($Pr.number): $($Pr.title)",
|
||||
" author: $author",
|
||||
" last updated $age days ago (threshold: $AgeDays days)",
|
||||
" labels: $labelText",
|
||||
" url: $($Pr.url)"
|
||||
) -join [Environment]::NewLine
|
||||
}
|
||||
|
||||
function Write-ReportLine {
|
||||
param(
|
||||
[Parameter(Mandatory)][AllowEmptyString()][string]$Text,
|
||||
[System.Collections.Generic.List[string]]$ReportLines
|
||||
)
|
||||
|
||||
if ($null -ne $ReportLines) {
|
||||
$ReportLines.Add($Text)
|
||||
}
|
||||
|
||||
[Console]::WriteLine($Text)
|
||||
}
|
||||
|
||||
function Test-GhAuthentication {
|
||||
$result = Invoke-GhCommand -Arguments @('auth', 'status')
|
||||
|
||||
if ($result.ExitCode -ne 0) {
|
||||
$message = ($result.Output | Out-String).Trim()
|
||||
throw "GitHub CLI is not authenticated. Run 'gh auth login' first. $message"
|
||||
}
|
||||
}
|
||||
|
||||
function Close-PullRequest {
|
||||
param(
|
||||
[Parameter(Mandatory)][hashtable]$Pr,
|
||||
[Parameter(Mandatory)][string]$Repo,
|
||||
[ValidateScript({ -not $_ -or (Test-Path -LiteralPath $_ -PathType Leaf) })]
|
||||
[string]$CommentFile
|
||||
)
|
||||
|
||||
$command = @('pr', 'close', [string]$Pr.number, '--repo', $Repo)
|
||||
if ($CommentFile) {
|
||||
$comment = Get-Content -LiteralPath $CommentFile -Raw
|
||||
$command += @('--comment', $comment)
|
||||
}
|
||||
|
||||
$result = Invoke-GhCommand -Arguments $command
|
||||
|
||||
if ($result.ExitCode -ne 0) {
|
||||
$message = ($result.Output | Out-String).Trim()
|
||||
throw "Unable to close PR #$($Pr.number): $message"
|
||||
}
|
||||
|
||||
return ($result.Output | Out-String)
|
||||
}
|
||||
|
||||
function Main {
|
||||
$reportLines = [System.Collections.Generic.List[string]]::new()
|
||||
$resolvedRepo = if ($env:GITHUB_REPOSITORY) { $env:GITHUB_REPOSITORY } else { $Repo }
|
||||
|
||||
if (-not (Get-Command gh -ErrorAction SilentlyContinue)) {
|
||||
Write-Error "'gh' is not available on PATH."
|
||||
return 1
|
||||
}
|
||||
|
||||
Test-GhAuthentication
|
||||
$cutoffDate = (Get-Date).ToUniversalTime().AddDays(-$Age).ToString('yyyy-MM-dd', [System.Globalization.CultureInfo]::InvariantCulture)
|
||||
$prs = Get-GhPrList -Repo $resolvedRepo -Limit $Limit -CutoffDate $cutoffDate
|
||||
|
||||
$stalePrs = @($prs | Sort-Object { [datetime]::Parse($_.updatedAt, [System.Globalization.CultureInfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::AssumeUniversal -bor [System.Globalization.DateTimeStyles]::AdjustToUniversal) })
|
||||
|
||||
if ($stalePrs.Count -eq 0) {
|
||||
Write-ReportLine -Text "No open PRs with no activity for $Age days or more found in $resolvedRepo." -ReportLines $reportLines
|
||||
|
||||
if ($OutputFile) {
|
||||
$directory = Split-Path -Path $OutputFile -Parent
|
||||
if ($directory -and -not (Test-Path -LiteralPath $directory -PathType Container)) {
|
||||
New-Item -ItemType Directory -Path $directory -Force | Out-Null
|
||||
}
|
||||
|
||||
Set-Content -LiteralPath $OutputFile -Value $reportLines -Encoding utf8NoBOM
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
Write-ReportLine -Text "Found $($stalePrs.Count) stale PR(s) in $resolvedRepo (threshold: $Age days since last update):" -ReportLines $reportLines
|
||||
Write-ReportLine -Text '' -ReportLines $reportLines
|
||||
|
||||
foreach ($pr in $stalePrs) {
|
||||
$reportText = Write-CandidateReport -Pr $pr -AgeDays $Age
|
||||
Write-ReportLine -Text $reportText -ReportLines $reportLines
|
||||
Write-ReportLine -Text '' -ReportLines $reportLines
|
||||
|
||||
if ($CloseWithComment) {
|
||||
Close-PullRequest -Pr $pr -Repo $resolvedRepo -CommentFile $CloseWithComment | Out-Null
|
||||
Write-ReportLine -Text " closed PR #$($pr.number) via gh pr close" -ReportLines $reportLines
|
||||
}
|
||||
else {
|
||||
Write-ReportLine -Text " would close PR #$($pr.number); pass -CloseWithComment to close it" -ReportLines $reportLines
|
||||
}
|
||||
}
|
||||
|
||||
if ($OutputFile) {
|
||||
$directory = Split-Path -Path $OutputFile -Parent
|
||||
if ($directory -and -not (Test-Path -LiteralPath $directory -PathType Container)) {
|
||||
New-Item -ItemType Directory -Path $directory -Force | Out-Null
|
||||
}
|
||||
|
||||
Set-Content -LiteralPath $OutputFile -Value $reportLines -Encoding utf8NoBOM
|
||||
}
|
||||
}
|
||||
|
||||
if ($MyInvocation.InvocationName -ne '.') {
|
||||
exit (Main)
|
||||
}
|
||||
Loading…
Reference in New Issue