##// END OF EJS Templates
truncate PR description in backported git msg to five lines...
truncate PR description in backported git msg to five lines sometimes these things are huge.

File last commit:

r16762:5c6d8139
r16762:5c6d8139
Show More
backport_pr.py
176 lines | 5.2 KiB | text/x-python | PythonLexer
MinRK
shebang backport_pr
r8347 #!/usr/bin/env python
MinRK
add backport_pr to tools...
r8346 """
Backport pull requests to a particular branch.
MinRK
allow backporting several PRs at once
r16761 Usage: backport_pr.py branch [PR] [PR2]
MinRK
add backport_pr to tools...
r8346
e.g.:
MinRK
allow backporting several PRs at once
r16761 python tools/backport_pr.py 0.13.1 123 155
MinRK
add backport_pr to tools...
r8346
to backport PR #123 onto branch 0.13.1
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424 or
MinRK
use milestones to indicate backport
r16167 python tools/backport_pr.py 2.1
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424
MinRK
use milestones to indicate backport
r16167 to see what PRs are marked for backport with milestone=2.1 that have yet to be applied
to branch 2.x.
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424
MinRK
add backport_pr to tools...
r8346 """
from __future__ import print_function
import os
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424 import re
MinRK
add backport_pr to tools...
r8346 import sys
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424
MinRK
add backport_pr to tools...
r8346 from subprocess import Popen, PIPE, check_call, check_output
Thomas Kluyver
Start making backport_pr work on Python 3
r16178 try:
from urllib.request import urlopen
except:
MinRK
allow backporting several PRs at once
r16761 from urllib import urlopen
MinRK
add backport_pr to tools...
r8346
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424 from gh_api import (
get_issues_list,
get_pull_request,
get_pull_request_files,
is_pull_request,
Skipper Seabold
Allow checking for backports via milestone
r13169 get_milestone_id,
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424 )
MinRK
add backport_pr to tools...
r8346
def find_rejects(root='.'):
for dirname, dirs, files in os.walk(root):
for fname in files:
if fname.endswith('.rej'):
yield os.path.join(dirname, fname)
def get_current_branch():
branches = check_output(['git', 'branch'])
for branch in branches.splitlines():
Thomas Kluyver
Start making backport_pr work on Python 3
r16178 if branch.startswith(b'*'):
return branch[1:].strip().decode('utf-8')
MinRK
add backport_pr to tools...
r8346
def backport_pr(branch, num, project='ipython/ipython'):
current_branch = get_current_branch()
if branch != current_branch:
check_call(['git', 'checkout', branch])
Thomas Kluyver
Update target branch before backporting PR
r12276 check_call(['git', 'pull'])
MinRK
get files list in backport_pr...
r12129 pr = get_pull_request(project, num, auth=True)
files = get_pull_request_files(project, num, auth=True)
MinRK
add backport_pr to tools...
r8346 patch_url = pr['patch_url']
title = pr['title']
description = pr['body']
fname = "PR%i.patch" % num
if os.path.exists(fname):
print("using patch from {fname}".format(**locals()))
with open(fname) as f:
patch = f.read()
else:
req = urlopen(patch_url)
patch = req.read()
Skipper Seabold
Allow checking for backports via milestone
r13169
MinRK
truncate PR description in backported git msg to five lines...
r16762 lines = description.splitlines()
if len(lines) > 5:
lines = lines[:5] + ['...']
description = '\n'.join(lines)
MinRK
add backport_pr to tools...
r8346 msg = "Backport PR #%i: %s" % (num, title) + '\n\n' + description
check = Popen(['git', 'apply', '--check', '--verbose'], stdin=PIPE)
a,b = check.communicate(patch)
Skipper Seabold
Allow checking for backports via milestone
r13169
MinRK
add backport_pr to tools...
r8346 if check.returncode:
print("patch did not apply, saving to {fname}".format(**locals()))
print("edit {fname} until `cat {fname} | git apply --check` succeeds".format(**locals()))
print("then run tools/backport_pr.py {num} again".format(**locals()))
if not os.path.exists(fname):
with open(fname, 'wb') as f:
f.write(patch)
return 1
Skipper Seabold
Allow checking for backports via milestone
r13169
MinRK
add backport_pr to tools...
r8346 p = Popen(['git', 'apply'], stdin=PIPE)
a,b = p.communicate(patch)
Skipper Seabold
Allow checking for backports via milestone
r13169
MinRK
get files list in backport_pr...
r12129 filenames = [ f['filename'] for f in files ]
MinRK
add backport_pr to tools...
r8346
MinRK
use check_call for git add and commit...
r12341 check_call(['git', 'add'] + filenames)
Skipper Seabold
Allow checking for backports via milestone
r13169
MinRK
use check_call for git add and commit...
r12341 check_call(['git', 'commit', '-m', msg])
Skipper Seabold
Allow checking for backports via milestone
r13169
MinRK
use check_call for git add and commit...
r12341 print("PR #%i applied, with msg:" % num)
print()
print(msg)
print()
Skipper Seabold
Allow checking for backports via milestone
r13169
MinRK
add backport_pr to tools...
r8346 if branch != current_branch:
check_call(['git', 'checkout', current_branch])
Skipper Seabold
Allow checking for backports via milestone
r13169
MinRK
add backport_pr to tools...
r8346 return 0
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424 backport_re = re.compile(r"[Bb]ackport.*?(\d+)")
def already_backported(branch, since_tag=None):
"""return set of PRs that have been backported already"""
if since_tag is None:
since_tag = check_output(['git','describe', branch, '--abbrev=0']).decode('utf8').strip()
cmd = ['git', 'log', '%s..%s' % (since_tag, branch), '--oneline']
lines = check_output(cmd).decode('utf8')
return set(int(num) for num in backport_re.findall(lines))
Skipper Seabold
Allow checking for backports via milestone
r13169 def should_backport(labels=None, milestone=None):
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424 """return set of PRs marked for backport"""
Skipper Seabold
Allow checking for backports via milestone
r13169 if labels is None and milestone is None:
raise ValueError("Specify one of labels or milestone.")
elif labels is not None and milestone is not None:
raise ValueError("Specify only one of labels or milestone.")
if labels is not None:
issues = get_issues_list("ipython/ipython",
labels=labels,
state='closed',
auth=True,
)
else:
milestone_id = get_milestone_id("ipython/ipython", milestone,
auth=True)
issues = get_issues_list("ipython/ipython",
milestone=milestone_id,
state='closed',
auth=True,
)
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424 should_backport = set()
for issue in issues:
if not is_pull_request(issue):
continue
Skipper Seabold
Allow checking for backports via milestone
r13169 pr = get_pull_request("ipython/ipython", issue['number'],
auth=True)
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424 if not pr['merged']:
print ("Marked PR closed without merge: %i" % pr['number'])
continue
MinRK
don't suggest backporting PRs against refs other than master
r16673 if pr['base']['ref'] != 'master':
continue
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424 should_backport.add(pr['number'])
return should_backport
MinRK
add backport_pr to tools...
r8346 if __name__ == '__main__':
Skipper Seabold
Allow checking for backports via milestone
r13169
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424 if len(sys.argv) < 2:
MinRK
add backport_pr to tools...
r8346 print(__doc__)
sys.exit(1)
Skipper Seabold
Allow checking for backports via milestone
r13169
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424 if len(sys.argv) < 3:
MinRK
use milestones to indicate backport
r16167 milestone = sys.argv[1]
branch = milestone.split('.')[0] + '.x'
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424 already = already_backported(branch)
MinRK
use milestones to indicate backport
r16167 should = should_backport(milestone=milestone)
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424 print ("The following PRs should be backported:")
MinRK
sort backport PRs
r13952 for pr in sorted(should.difference(already)):
MinRK
add ability to check what PRs should be backported in backport_pr...
r12424 print (pr)
sys.exit(0)
Skipper Seabold
Allow checking for backports via milestone
r13169
MinRK
allow backporting several PRs at once
r16761 for prno in map(int, sys.argv[2:]):
print("Backporting PR #%i" % prno)
rc = backport_pr(sys.argv[1], prno)
if rc:
print("Backporting PR #%i failed" % prno)
sys.exit(rc)