44
55Instructions on how to install gh can be found here: https://github.com/cli/cli#installation
66"""
7- import json
8- import os
97import click
8+ import json
9+ import subprocess
10+ from time import sleep
1011from typing import NoReturn
1112
1213
@@ -15,6 +16,13 @@ def cli():
1516 pass
1617
1718
19+ def run_command (command : str ) -> str :
20+ """Utility function to run commands."""
21+ process = subprocess .Popen (command , stdout = subprocess .PIPE , stderr = subprocess .PIPE , shell = True )
22+ output , _ = process .communicate ()
23+ return output .decode ("utf-8" )
24+
25+
1826@cli .command ()
1927@click .option (
2028 "--label" ,
@@ -25,14 +33,46 @@ def cli():
2533)
2634def bulk_merge (label : str ) -> NoReturn :
2735 """Utility function to assist with bulk merging pull requests."""
28- gh_pr_list_command = f"gh pr list -s open -l { label } --json number"
29- gh_pr_bulk_merge_command = "gh pr merge -s -d"
36+ gh_pr_list_command = f"gh pr list -s open -l { label } --json title,number"
37+ gh_pr_bulk_merge_command = "gh pr merge -s -d --admin"
38+
39+ click .echo (f"Fetching open PRs with { label } label..." )
40+ pull_requests = json .loads (run_command (gh_pr_list_command ))
3041
31- stream = os .popen (gh_pr_list_command )
32- pull_requests = json .loads (stream .read ())
42+ if not pull_requests :
43+ click .echo (f"No open PRs with { label } label found." )
44+ return
3345
3446 for pull_request in pull_requests :
35- stream = os .popen (f"{ gh_pr_bulk_merge_command } { pull_request ['number' ]} " )
47+ number = pull_request ["number" ]
48+ title = pull_request ["title" ]
49+ click .echo (f"Merging PR #{ number } { title } ..." )
50+ run_command (f"{ gh_pr_bulk_merge_command } { number } " )
51+ sleep (
52+ 5
53+ ) # NOTE: Needed to avoid error "Base branch was modified. Review and try the merge again"
54+
55+ click .echo (f"Open PRs with { label } label merged." )
56+
57+
58+ def is_excluded_label (label : str , exclude_labels : list ) -> bool :
59+ """Checks if label is in the excluded labels list."""
60+ return label ["name" ] in exclude_labels
61+
62+
63+ def is_excluded_author (pull_request : dict , exclude_bot_authors : bool ) -> bool :
64+ """Checks if author is a bot."""
65+ return exclude_bot_authors and pull_request ["author" ]["is_bot" ]
66+
67+
68+ def update_section (
69+ pull_request : dict , sections : dict , label_name : str , dispatch_pr_url : str
70+ ) -> NoReturn :
71+ """Updates release notes section."""
72+ title = pull_request ["title" ]
73+ number = pull_request ["number" ]
74+ author = pull_request ["author" ]["login" ]
75+ sections [label_name ] += f"\n * { title } ([#{ number } ]({ dispatch_pr_url } { number } )) by @{ author } "
3676
3777
3878@cli .command ()
@@ -49,10 +89,6 @@ def release_notes(pull_request_number: int) -> NoReturn:
4989 exclude_bot_authors = True
5090 exclude_labels = ["skip-changelog" , "UI/UX" , "javascript" ]
5191 gh_pr_list_merged_command = 'gh pr list -s merged --json "title,author,number,labels" -L 250'
52-
53- stream = os .popen (gh_pr_list_merged_command )
54- pull_requests = json .loads (stream .read ())
55-
5692 sections = {
5793 "bug" : "" ,
5894 "dependencies" : "" ,
@@ -63,27 +99,26 @@ def release_notes(pull_request_number: int) -> NoReturn:
6399 "tests" : "" ,
64100 }
65101
102+ click .echo (f"Fetching list of merged PRs since #{ pull_request_number } ..." )
103+ pull_requests = json .loads (run_command (gh_pr_list_merged_command ))
104+
105+ if not pull_requests :
106+ click .echo (f"No PRs merged since #{ pull_request_number } ." )
107+
66108 for pull_request in pull_requests :
67- author = pull_request ["author" ]["login" ]
68- is_bot_author = pull_request ["author" ]["is_bot" ]
69- title = pull_request ["title" ]
70109 number = pull_request ["number" ]
71110
72111 if number < pull_request_number :
73112 break
74113
75- if exclude_bot_authors and is_bot_author :
114+ if is_excluded_author ( pull_request , exclude_bot_authors ) :
76115 continue
77116
78117 for label in pull_request ["labels" ]:
79- label_name = label ["name" ]
80- if label_name in exclude_labels :
118+ if is_excluded_label (label , exclude_labels ):
81119 continue
82120
83- sections [label_name ] = (
84- sections [label_name ]
85- + f"\n * { title } ([#{ number } ]({ dispatch_pr_url } { number } )) by @{ author } "
86- )
121+ update_section (pull_request , sections , label ["name" ], dispatch_pr_url )
87122
88123 print (
89124 f"""
0 commit comments