11from os import getenv
2+ from typing import Optional
23
34import requests
45
56
67def get_github_prs (token : str , owner : str , repo : str , label : str = "" , state : str = "all" ) -> list [dict ]:
78 """
8- Fetches pull requests from a GitHub repository that match a given milestone and label .
9+ Fetches pull requests from a GitHub repository that match a given label and state .
910
1011 Args:
1112 token (str): GitHub token.
@@ -23,39 +24,10 @@ def get_github_prs(token: str, owner: str, repo: str, label: str = "", state: st
2324 "Accept" : "application/vnd.github.v3+json" ,
2425 }
2526
26- milestone_id = None
27- milestone_url = f"https://api.github.com/repos/{ owner } /{ repo } /milestones"
28- params = {"state" : "open" }
29-
30- try :
31- response = requests .get (milestone_url , headers = headers , params = params )
32- response .raise_for_status ()
33- milestones = response .json ()
34-
35- if len (milestones ) > 2 :
36- print ("More than two milestones found, unable to determine the milestone required." )
37- exit (1 )
38-
39- # milestones.pop()
40- for ms in milestones :
41- if ms ["title" ] != "Future" :
42- milestone_id = ms ["number" ]
43- print (f"Gathering PRs with milestone { ms ['title' ]} ..." )
44- break
45-
46- if not milestone_id :
47- print (f"No suitable milestone found in repository '{ owner } /{ repo } '." )
48- exit (1 )
49-
50- except requests .exceptions .RequestException as e :
51- print (f"Error fetching milestones: { e } " )
52- exit (1 )
53-
54- # This endpoint allows filtering by milestone and label. A PR in GH's perspective is a type of issue.
27+ # This endpoint allows filtering by label(and milestone). A PR in GH's perspective is a type of issue.
5528 prs_url = f"https://api.github.com/repos/{ owner } /{ repo } /issues"
5629 params = {
5730 "state" : state ,
58- "milestone" : milestone_id ,
5931 "labels" : label ,
6032 "per_page" : 100 ,
6133 }
@@ -83,14 +55,18 @@ def get_github_prs(token: str, owner: str, repo: str, label: str = "", state: st
8355 return all_prs
8456
8557
86- def get_prs (pull_request_items : list [dict ], label : str = "" , state : str = "all" ) -> list [dict ]:
58+ def get_prs (
59+ pull_request_items : list [dict ], label : str = "" , state : str = "all" , milestone_title : Optional [str ] = None
60+ ) -> list [dict ]:
8761 """
8862 Returns a list of pull requests after applying the label and state filters.
8963
9064 Args:
9165 pull_request_items (list[dict]): List of PR items.
9266 label (str): The label name. Filter is not applied when empty string.
9367 state (str): State of PR, e.g. open, closed, all
68+ milestone_title (Optional[str]): The milestone title to filter by. This is the milestone number you created
69+ in GitHub, e.g. '1.20.0'. If None, no milestone filtering is applied.
9470
9571 Returns:
9672 list: A list of dictionaries, where each dictionary represents a pull request.
@@ -99,22 +75,32 @@ def get_prs(pull_request_items: list[dict], label: str = "", state: str = "all")
9975 pr_list = []
10076 count = 0
10177 for pr in pull_request_items :
102- if state in [pr ["state" ], "all" ] and (not label or [item for item in pr ["labels" ] if item ["name" ] == label ]):
103- pr_list .append (pr )
104- count += 1
78+ if state not in [pr ["state" ], "all" ]:
79+ continue
80+
81+ if label and not [item for item in pr ["labels" ] if item ["name" ] == label ]:
82+ continue
10583
106- print (f"Found { count } PRs with { label if label else 'no filter on' } label and state as { state } " )
84+ if milestone_title :
85+ if pr ["milestone" ] is None or pr ["milestone" ]["title" ] != milestone_title :
86+ continue
87+
88+ pr_list .append (pr )
89+ count += 1
90+
91+ print (
92+ f"Found { count } PRs with { label if label else 'no filter on' } label, state as { state } , and milestone { pr ["milestone" ] if pr ["milestone" ] is not None else "None" } "
93+ )
10794
10895 return pr_list
10996
110- def get_prs_assignees (pull_request_items : list [dict ], label : str = "" , state : str = "all" ) -> list [str ]:
97+
98+ def get_prs_assignees (pull_request_items : list [dict ]) -> list [str ]:
11199 """
112- Returns a list of pull request assignees after applying the label and state filters , excludes jjw24.
100+ Returns a list of pull request assignees, excludes jjw24.
113101
114102 Args:
115- pull_request_items (list[dict]): List of PR items.
116- label (str): The label name. Filter is not applied when empty string.
117- state (str): State of PR, e.g. open, closed, all
103+ pull_request_items (list[dict]): List of PR items to get the assignees from.
118104
119105 Returns:
120106 list: A list of strs, where each string is an assignee name. List is not distinct, so can contain
@@ -123,13 +109,13 @@ def get_prs_assignees(pull_request_items: list[dict], label: str = "", state: st
123109 """
124110 assignee_list = []
125111 for pr in pull_request_items :
126- if state in [pr ["state" ], "all" ] and (not label or [item for item in pr ["labels" ] if item ["name" ] == label ]):
127- [assignee_list .append (assignee ["login" ]) for assignee in pr ["assignees" ] if assignee ["login" ] != "jjw24" ]
112+ [assignee_list .append (assignee ["login" ]) for assignee in pr ["assignees" ] if assignee ["login" ] != "jjw24" ]
128113
129- print (f"Found { len (assignee_list )} assignees with { label if label else 'no filter on' } label and state as { state } " )
114+ print (f"Found { len (assignee_list )} assignees" )
130115
131116 return assignee_list
132117
118+
133119def get_pr_descriptions (pull_request_items : list [dict ]) -> str :
134120 """
135121 Returns the concatenated string of pr title and number in the format of
@@ -207,30 +193,42 @@ def update_pull_request_description(token: str, owner: str, repo: str, pr_number
207193
208194 print (f"Fetching { state } PRs for { repository_owner } /{ repository_name } ..." )
209195
210- pull_requests = get_github_prs (github_token , repository_owner , repository_name )
196+ # First, get all PRs to find the release PR and determine the milestone
197+ all_pull_requests = get_github_prs (github_token , repository_owner , repository_name )
211198
212- if not pull_requests :
213- print ("No matching pull requests found" )
199+ if not all_pull_requests :
200+ print ("No pull requests found" )
214201 exit (1 )
215202
216- print (f"\n Found total of { len (pull_requests )} pull requests" )
203+ print (f"\n Found total of { len (all_pull_requests )} pull requests" )
217204
218- release_pr = get_prs (pull_requests , "release" , "open" )
205+ release_pr = get_prs (all_pull_requests , "release" , "open" )
219206
220207 if len (release_pr ) != 1 :
221208 print (f"Unable to find the exact release PR. Returned result: { release_pr } " )
222209 exit (1 )
223210
224211 print (f"Found release PR: { release_pr [0 ]['title' ]} " )
225212
226- enhancement_prs = get_prs (pull_requests , "enhancement" , "closed" )
227- bug_fix_prs = get_prs (pull_requests , "bug" , "closed" )
213+ release_milestone_title = release_pr [0 ].get ("milestone" , {}).get ("title" , None )
214+
215+ if not release_milestone_title :
216+ print ("Release PR does not have a milestone assigned." )
217+ exit (1 )
218+
219+ print (f"Using milestone number: { release_milestone_title } " )
220+
221+ enhancement_prs = get_prs (all_pull_requests , "enhancement" , "closed" , release_milestone_title )
222+ bug_fix_prs = get_prs (all_pull_requests , "bug" , "closed" , release_milestone_title )
223+
224+ if len (enhancement_prs ) == 0 and len (bug_fix_prs ) == 0 :
225+ print (f"No PRs with { release_milestone_title } milestone were found" )
228226
229227 description_content = "# Release notes\n "
230228 description_content += f"## Features\n { get_pr_descriptions (enhancement_prs )} " if enhancement_prs else ""
231229 description_content += f"## Bug fixes\n { get_pr_descriptions (bug_fix_prs )} " if bug_fix_prs else ""
232230
233- assignees = list (set (get_prs_assignees (pull_requests , "enhancement" , "closed" ) + get_prs_assignees (pull_requests , "bug" , "closed" )))
231+ assignees = list (set (get_prs_assignees (enhancement_prs ) + get_prs_assignees (bug_fix_prs )))
234232 assignees .sort (key = str .lower )
235233
236234 description_content += f"### Authors:\n { ', ' .join (assignees )} "
0 commit comments