Skip to content

Commit 46f2dd6

Browse files
author
Yeming Liu
committed
Add Merge-DevPullRequest cmdlet and update documentation
- Introduced `Merge-DevPullRequest` cmdlet to facilitate merging pull requests in the azure-powershell repository. - Updated README.md to include usage instructions for the new cmdlet. - Added entry to CHANGELOG.md for the new feature. - Modified AzDev.psd1 to export the new cmdlet and its alias.
1 parent 1e0e6bd commit 46f2dd6

File tree

4 files changed

+238
-3
lines changed

4 files changed

+238
-3
lines changed

tools/AzDev/AzDev/AzDev.psd1

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,11 @@ FormatsToProcess = @('AzDev.format.ps1xml')
6767

6868
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
6969
NestedModules = @('bin/AzDev.dll',
70-
'CommonRepo.psm1')
70+
'CommonRepo.psm1',
71+
'GitHub.psm1')
7172

7273
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
73-
FunctionsToExport = 'Connect-DevCommonRepo', 'Disconnect-DevCommonRepo'
74+
FunctionsToExport = 'Connect-DevCommonRepo', 'Disconnect-DevCommonRepo', 'Merge-DevPullRequest'
7475

7576
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
7677
CmdletsToExport = 'Get-DevContext', 'Set-DevContext',
@@ -82,7 +83,7 @@ CmdletsToExport = 'Get-DevContext', 'Set-DevContext',
8283
VariablesToExport = '*'
8384

8485
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
85-
AliasesToExport = '*'
86+
AliasesToExport = 'Merge-DevPR'
8687

8788
# DSC resources to export from this module
8889
# DscResourcesToExport = @()

tools/AzDev/AzDev/GitHub.psm1

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
function Merge-DevPullRequest {
2+
<#
3+
.SYNOPSIS
4+
Merges pull requests in the azure-powershell repository.
5+
6+
.DESCRIPTION
7+
Helps merge pull requests in the azure-powershell repo. When using -AllArchivePR, for safety,
8+
it only supports merging PRs with the "[skip ci]" prefix in the title and created by the
9+
"azure-powershell-bot" user, which are the archive PRs for generated modules.
10+
When using -Number, any PR can be merged.
11+
12+
.PARAMETER Number
13+
The pull request number(s) to merge. Can be a single number or an array of numbers.
14+
15+
.PARAMETER AllArchivePR
16+
Lists all matching PRs (ordered by CreatedAt ascending) and prompts for confirmation before merging.
17+
18+
.PARAMETER Approve
19+
Approve the pull request before merging.
20+
21+
.PARAMETER Force
22+
Skip confirmation prompts.
23+
24+
.EXAMPLE
25+
Merge-DevPullRequest -Approve -Number 28690
26+
27+
.EXAMPLE
28+
Merge-DevPullRequest -Approve -Number 28690, 28691, 28692
29+
30+
.EXAMPLE
31+
Merge-DevPullRequest -Approve -AllArchivePR -Force
32+
33+
.NOTES
34+
Requires GitHub CLI to be installed and authenticated (gh auth login).
35+
#>
36+
[CmdletBinding(DefaultParameterSetName = 'Single')]
37+
[Alias('Merge-DevPR')]
38+
param(
39+
[Parameter(Mandatory = $true, ParameterSetName = 'Single')]
40+
[int[]]$Number,
41+
42+
[Parameter(Mandatory = $true, ParameterSetName = 'All')]
43+
[switch]$AllArchivePR,
44+
45+
[switch]$Approve,
46+
47+
[switch]$Force
48+
)
49+
50+
# Check if GitHub CLI is available
51+
try {
52+
gh --version | Out-Null
53+
}
54+
catch {
55+
throw "GitHub CLI is not installed or not in PATH. Please install GitHub CLI and authenticate with 'gh auth login'."
56+
}
57+
58+
# Check if authenticated
59+
try {
60+
gh auth status | Out-Null
61+
}
62+
catch {
63+
throw "GitHub CLI is not authenticated. Please run 'gh auth login' first."
64+
}
65+
66+
$mergedPRs = @()
67+
$failedPRs = @()
68+
69+
if ($PSCmdlet.ParameterSetName -eq 'Single') {
70+
# Get PR details for each number
71+
$prsToMerge = @()
72+
foreach ($prNumber in $Number) {
73+
try {
74+
$prJson = gh pr view $prNumber --json number,title,author,createdAt,url 2>$null
75+
if ($LASTEXITCODE -ne 0) {
76+
throw "Pull request #$prNumber not found."
77+
}
78+
$pr = $prJson | ConvertFrom-Json
79+
$prsToMerge += $pr
80+
}
81+
catch {
82+
throw "Failed to get pull request #$prNumber`: $_"
83+
}
84+
}
85+
}
86+
else {
87+
# Get all archive PRs
88+
try {
89+
$allPRsJson = gh pr list --state open --author azure-powershell-bot --json number,title,author,createdAt,url 2>$null
90+
if ($LASTEXITCODE -ne 0) {
91+
throw "Failed to list pull requests."
92+
}
93+
$allPRs = $allPRsJson | ConvertFrom-Json
94+
}
95+
catch {
96+
throw "Failed to list pull requests: $_"
97+
}
98+
99+
# Filter for archive PRs (with [skip ci] prefix)
100+
$archivePRs = $allPRs | Where-Object { $_.title.StartsWith('[skip ci]') } | Sort-Object createdAt
101+
102+
if ($archivePRs.Count -eq 0) {
103+
Write-Host "No archive PRs found matching criteria."
104+
return @()
105+
}
106+
107+
$prsToMerge = $archivePRs
108+
}
109+
110+
# Display PRs to be merged
111+
if ($prsToMerge.Count -gt 0) {
112+
if (-not $Force) {
113+
$confirmMessage = "Do you want to"
114+
if ($Approve) { $confirmMessage += " approve and" }
115+
$confirmMessage += " merge the following pull request$(if($prsToMerge.Count -gt 1){'s'})?"
116+
Write-Host $confirmMessage
117+
}
118+
119+
# Format and display PRs
120+
$prTable = $prsToMerge | ForEach-Object {
121+
[PSCustomObject]@{
122+
'No.' = $_.number
123+
'Title' = $_.title
124+
'CreatedBy' = $_.author.login
125+
'CreatedAt' = [DateTime]::Parse($_.createdAt).ToString('M/d/yyyy h:mm:ss tt')
126+
'Url' = $_.url
127+
}
128+
}
129+
130+
$prTable | Format-Table -AutoSize | Out-String | Write-Host
131+
132+
# Confirmation prompt (for both parameter sets unless Force is used)
133+
if (-not $Force) {
134+
do {
135+
$response = Read-Host "Type Y to$(if($Approve){' approve and'}) merge, N to cancel"
136+
} while ($response -notin @('Y', 'y', 'N', 'n'))
137+
138+
if ($response -in @('N', 'n')) {
139+
Write-Host "Operation cancelled."
140+
return @()
141+
}
142+
}
143+
}
144+
145+
# Merge PRs
146+
foreach ($pr in $prsToMerge) {
147+
try {
148+
Write-Host "Processing PR #$($pr.number)..." -ForegroundColor Yellow
149+
150+
# Approve if requested
151+
if ($Approve) {
152+
Write-Host " Approving PR #$($pr.number)..." -ForegroundColor Cyan
153+
gh pr review $pr.number --approve 2>$null
154+
if ($LASTEXITCODE -ne 0) {
155+
throw "Failed to approve PR #$($pr.number)"
156+
}
157+
}
158+
159+
# Merge PR
160+
Write-Host " Merging PR #$($pr.number)..." -ForegroundColor Cyan
161+
gh pr merge $pr.number --squash 2>$null
162+
if ($LASTEXITCODE -ne 0) {
163+
throw "Failed to merge PR #$($pr.number)"
164+
}
165+
166+
Write-Host " Successfully merged PR #$($pr.number)" -ForegroundColor Green
167+
$mergedPRs += $pr
168+
}
169+
catch {
170+
Write-Error "Failed to merge PR #$($pr.number): $_"
171+
$failedPRs += $pr
172+
}
173+
}
174+
175+
# Report results
176+
if ($mergedPRs.Count -gt 0) {
177+
Write-Host "`nSuccessfully merged $($mergedPRs.Count) pull request(s)." -ForegroundColor Green
178+
}
179+
180+
if ($failedPRs.Count -gt 0) {
181+
$errorMessage = "Failed to merge $($failedPRs.Count) pull request(s): $($failedPRs.number -join ', ')"
182+
Write-Error $errorMessage
183+
throw $errorMessage
184+
}
185+
186+
# Return merged PRs in the format shown in README
187+
return $mergedPRs | ForEach-Object {
188+
[PSCustomObject]@{
189+
'No.' = $_.number
190+
'Title' = $_.title
191+
'CreatedBy' = $_.author.login
192+
'CreatedAt' = [DateTime]::Parse($_.createdAt).ToString('M/d/yyyy h:mm:ss tt')
193+
'Url' = $_.url
194+
}
195+
}
196+
}
197+
198+
Export-ModuleMember -Function Merge-DevPullRequest -Alias Merge-DevPR

tools/AzDev/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
- Quick start templates
1111
- Versioning and publishing AzDev module
1212

13+
## 2025/10/20
14+
- Feature: `Merge-DevPullRequest` cmdlet to help merge PRs in azure-powershell repo.
15+
1316
## 2025/8/26
1417
- Feature: Recognize AutoRest.PowerShell version (v3/v4) for AutoRest-based projects and show as `SubType` in `Get-DevProject` output.
1518

tools/AzDev/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Like many other tools, this module targets `net8.0` so always run it in PowerShe
1313
- [Connect azure-powershell and azure-powershell-common](#connect-azure-powershell-and-azure-powershell-common)
1414
- [Autorest helper](#autorest-helper)
1515
- [Open swagger online](#open-swagger-online)
16+
- [GitHub Helpers](#github-helpers)
17+
- [Merge PRs](#merge-prs)
1618
- [Development](#development)
1719
- [Design](#design)
1820
- [Testing](#testing)
@@ -116,6 +118,37 @@ Enter the number corresponding to your selection
116118
Opening https://github.com/Azure/azure-rest-api-specs/blob/202321f386ea5b0c103b46902d43b3d3c50e029c/specification/workloads/resource-manager/Microsoft.Workloads/SAPVirtualInstance/readme.md in default browser...
117119
```
118120

121+
### GitHub Helpers
122+
123+
Prerequisite: You need to install [GitHub CLI](https://cli.github.com/) and set up GitHub authentication first with `gh auth login`.
124+
125+
#### Merge PRs
126+
127+
`Merge-DevPullRequest` (alias: `Merge-DevPR`) helps you merge pull requests in the azure-powershell repo. It supports two parameter sets: merging a specific PR by number, and merging all archive PRs.
128+
129+
With the `-AllArchivePR` switch, the cmdlet lists all the matching PRs, ordered by CreatedAt ascending, and prompts you to confirm before merging. Use the `-Force` switch to skip the confirmation. For safety, this parameter set only supports merging PRs with the "[skip ci]" prefix in the title and created by the `azure-powershell-bot` user, which are the archive PRs for generated modules.
130+
131+
The cmdlet returns the list of merged PRs. In case any PR fails to merge, an error is thrown, and the successfully merged PRs are still returned.
132+
133+
```powershell
134+
PS C:\> Merge-DevPullRequest -Approve -Number 28690
135+
136+
Do you want to approve and merge the following pull request?
137+
- 28690 [skip ci] Archive e36b0a91ac13ad8c173760dab2d1c038495d41cc
138+
Type Y to approve and merge, N to cancel: Y
139+
140+
No. Title CreatedBy CreatedAt Url
141+
--- ----- --------- --------- ---
142+
28690 [skip ci] Archive e36b0a91ac13ad8c173760dab2d1c038495d41cc azure-powershell-bot 6/10/2024 2:15:30 PM
143+
144+
PS C:\> Merge-DevPullRequest -Approve -AllArchivePR -Force
145+
146+
No. Title CreatedBy CreatedAt Url
147+
--- ----- --------- --------- ---
148+
28690 [skip ci] Archive e36b0a91ac13ad8c173760dab2d1c038495d41cc azure-powershell-bot 6/10/2024 2:15:30 PM
149+
28689 [skip ci] Archive deed8db801365cc26557b46c7a8a01d134f0b524 azure-powershell-bot 6/29/2024 11:05:12 AM
150+
```
151+
119152
## Development
120153

121154
### Design

0 commit comments

Comments
 (0)