3131import subprocess
3232import sys
3333import traceback
34+ import requests
3435from urllib .request import urlopen
3536from urllib .request import Request
3637from urllib .error import HTTPError
@@ -89,6 +90,24 @@ def get_json(url):
8990 sys .exit (- 1 )
9091
9192
93+ def get_pull_request (pr_num ):
94+ headers = {
95+ "Authorization" : f"token { GITHUB_OAUTH_KEY } " ,
96+ "Accept" : "application/vnd.github.v3+json" ,
97+ }
98+ response = requests .get (
99+ f"{ GITHUB_API_BASE } /pulls/{ pr_num } " ,
100+ headers = headers ,
101+ )
102+ if response .status_code == 200 :
103+ return response .json ()
104+ else :
105+ error_message = (f"Failed to get pull request #{ pr_num } . "
106+ f"Status code: { response .status_code } " )
107+ error_message += f"\n Response: { response .text } "
108+ fail (error_message )
109+
110+
92111def fail (msg ):
93112 print (msg )
94113 clean_up ()
@@ -129,19 +148,26 @@ def merge_pr(pr_num, target_ref, title, body, pr_repo_desc):
129148 run_cmd ("git fetch %s %s:%s" % (PUSH_REMOTE_NAME , target_ref , target_branch_name ))
130149 run_cmd ("git checkout %s" % target_branch_name )
131150
132- had_conflicts = False
133- try :
134- run_cmd (["git" , "merge" , pr_branch_name , "--squash" ])
135- except Exception as e :
136- msg = "Error merging: %s\n Would you like to manually fix-up this merge?" % e
137- continue_maybe (msg )
138- msg = "Okay, please fix any conflicts and 'git add' conflicting files... Finished?"
139- continue_maybe (msg )
140- had_conflicts = True
151+ # Get all the data from the pull request.
152+ pr = get_pull_request (pr_num )
153+
154+ # Check if the PR is mergeable and still open:
155+ if not pr ["mergeable" ]:
156+ fail (f"Pull request #{ pr_num } is not mergeable in its current form." )
157+
158+ # Check if the PR is still open.
159+ if pr ["state" ] != "open" :
160+ fail (f"Pull request #{ pr_num } is not open." )
161+
162+ if pr ["merged" ]:
163+ fail (f"Pull request #{ pr_num } has already been merged." )
164+
165+ if pr ["draft" ]:
166+ fail (f"Pull request #{ pr_num } is a draft." )
141167
142168 # First commit author should be considered as the primary author when the rank is the same
143169 commit_authors = run_cmd (
144- ["git" , "log" , "HEAD ..%s" % pr_branch_name , "--pretty=format:%an <%ae>" , "--reverse" ]
170+ ["git" , "log" , "%s ..%s" % ( target_branch_name , pr_branch_name ) , "--pretty=format:%an <%ae>" , "--reverse" ]
145171 ).split ("\n " )
146172 distinct_authors = sorted (
147173 list (dict .fromkeys (commit_authors )), key = lambda x : commit_authors .count (x ), reverse = True
@@ -157,52 +183,61 @@ def merge_pr(pr_num, target_ref, title, body, pr_repo_desc):
157183 distinct_authors = list (filter (lambda x : x != primary_author , distinct_authors ))
158184 distinct_authors .insert (0 , primary_author )
159185
160- merge_message_flags = []
161-
162- merge_message_flags += ["-m" , title ]
186+ merge_message = ""
163187 if body is not None :
164188 # We remove @ symbols from the body to avoid triggering e-mails
165189 # to people every time someone creates a public fork of Spark.
166- merge_message_flags += [ "-m" , body .replace ("@" , "" )]
190+ merge_message += body .replace ("@" , "" )
167191
168192 committer_name = run_cmd ("git config --get user.name" ).strip ()
169193 committer_email = run_cmd ("git config --get user.email" ).strip ()
170194
171- if had_conflicts :
172- message = "This patch had conflicts when merged, resolved by\n Committer: %s <%s>" % (
173- committer_name ,
174- committer_email ,
175- )
176- merge_message_flags += ["-m" , message ]
177-
178195 # The string "Closes #%s" string is required for GitHub to correctly close the PR
179- merge_message_flags += ["-m" , "Closes #%s from %s." % (pr_num , pr_repo_desc )]
196+ merge_message += "\n \n "
197+ merge_message += "Closes #%s from %s." % (pr_num , pr_repo_desc )
180198
181199 authors = "Authored-by:" if len (distinct_authors ) == 1 else "Lead-authored-by:"
182200 authors += " %s" % (distinct_authors .pop (0 ))
183201 if len (distinct_authors ) > 0 :
184202 authors += "\n " + "\n " .join (["Co-authored-by: %s" % a for a in distinct_authors ])
185203 authors += "\n " + "Signed-off-by: %s <%s>" % (committer_name , committer_email )
186204
187- merge_message_flags += ["-m" , authors ]
188-
189- run_cmd (["git" , "commit" , '--author="%s"' % primary_author ] + merge_message_flags )
190-
191- continue_maybe (
192- "Merge complete (local ref %s). Push to %s?" % (target_branch_name , PUSH_REMOTE_NAME )
205+ merge_message += "\n \n "
206+ merge_message += authors
207+
208+ # Merge the Pull Request using the commit message and title and squash it.
209+ headers = {
210+ "Authorization" : f"token { GITHUB_OAUTH_KEY } " ,
211+ "Accept" : "application/vnd.github.v3+json" ,
212+ }
213+
214+ data = {
215+ "commit_title" : title ,
216+ "commit_message" : merge_message ,
217+ # Must be squash, always.
218+ "merge_method" : "squash" ,
219+ }
220+
221+ continue_maybe ("Collected all data. Ready to merge PR?" )
222+
223+ # Run the request to merge the PR.
224+ response = requests .put (
225+ f"{ GITHUB_API_BASE } /pulls/{ pr_num } /merge" ,
226+ headers = headers ,
227+ json = data
193228 )
194229
195- try :
196- run_cmd ("git push %s %s:%s" % (PUSH_REMOTE_NAME , target_branch_name , target_ref ))
197- except Exception as e :
230+ if response .status_code == 200 :
231+ merge_response_json = response .json ()
232+ merge_commit_sha = merge_response_json .get ("sha" )
233+ print (f"Pull request #{ pr_num } merged. Sha: #{ merge_commit_sha } " )
198234 clean_up ()
199- fail ("Exception while pushing: %s" % e )
200-
201- merge_hash = run_cmd ("git rev-parse %s" % target_branch_name )[:8 ]
202- clean_up ()
203- print ("Pull request #%s merged!" % pr_num )
204- print ("Merge hash: %s" % merge_hash )
205- return merge_hash
235+ return merge_commit_sha
236+ else :
237+ error_message = f"Failed to merge pull request #{ pr_num } . Status code: { response .status_code } "
238+ error_message += f"\n Response: { response .text } "
239+ clean_up ()
240+ fail (error_message )
206241
207242
208243def cherry_pick (pr_num , merge_hash , default_branch ):
0 commit comments