##// END OF EJS Templates
shebang backport_pr
MinRK -
Show More
@@ -1,89 +1,90 b''
1 #!/usr/bin/env python
1 """
2 """
2 Backport pull requests to a particular branch.
3 Backport pull requests to a particular branch.
3
4
4 Usage: backport_pr.py branch PR
5 Usage: backport_pr.py branch PR
5
6
6 e.g.:
7 e.g.:
7
8
8 backport_pr.py 0.13.1 123
9 backport_pr.py 0.13.1 123
9
10
10 to backport PR #123 onto branch 0.13.1
11 to backport PR #123 onto branch 0.13.1
11
12
12 """
13 """
13
14
14 from __future__ import print_function
15 from __future__ import print_function
15
16
16 import os
17 import os
17 import sys
18 import sys
18 from subprocess import Popen, PIPE, check_call, check_output
19 from subprocess import Popen, PIPE, check_call, check_output
19 from urllib import urlopen
20 from urllib import urlopen
20
21
21 from gh_api import get_pull_request
22 from gh_api import get_pull_request
22
23
23 def find_rejects(root='.'):
24 def find_rejects(root='.'):
24 for dirname, dirs, files in os.walk(root):
25 for dirname, dirs, files in os.walk(root):
25 for fname in files:
26 for fname in files:
26 if fname.endswith('.rej'):
27 if fname.endswith('.rej'):
27 yield os.path.join(dirname, fname)
28 yield os.path.join(dirname, fname)
28
29
29 def get_current_branch():
30 def get_current_branch():
30 branches = check_output(['git', 'branch'])
31 branches = check_output(['git', 'branch'])
31 for branch in branches.splitlines():
32 for branch in branches.splitlines():
32 if branch.startswith('*'):
33 if branch.startswith('*'):
33 return branch[1:].strip()
34 return branch[1:].strip()
34
35
35 def backport_pr(branch, num, project='ipython/ipython'):
36 def backport_pr(branch, num, project='ipython/ipython'):
36 current_branch = get_current_branch()
37 current_branch = get_current_branch()
37 if branch != current_branch:
38 if branch != current_branch:
38 check_call(['git', 'checkout', branch])
39 check_call(['git', 'checkout', branch])
39 pr = get_pull_request(project, num)
40 pr = get_pull_request(project, num)
40 patch_url = pr['patch_url']
41 patch_url = pr['patch_url']
41 title = pr['title']
42 title = pr['title']
42 description = pr['body']
43 description = pr['body']
43 fname = "PR%i.patch" % num
44 fname = "PR%i.patch" % num
44 if os.path.exists(fname):
45 if os.path.exists(fname):
45 print("using patch from {fname}".format(**locals()))
46 print("using patch from {fname}".format(**locals()))
46 with open(fname) as f:
47 with open(fname) as f:
47 patch = f.read()
48 patch = f.read()
48 else:
49 else:
49 req = urlopen(patch_url)
50 req = urlopen(patch_url)
50 patch = req.read()
51 patch = req.read()
51
52
52 msg = "Backport PR #%i: %s" % (num, title) + '\n\n' + description
53 msg = "Backport PR #%i: %s" % (num, title) + '\n\n' + description
53 check = Popen(['git', 'apply', '--check', '--verbose'], stdin=PIPE)
54 check = Popen(['git', 'apply', '--check', '--verbose'], stdin=PIPE)
54 a,b = check.communicate(patch)
55 a,b = check.communicate(patch)
55
56
56 if check.returncode:
57 if check.returncode:
57 print("patch did not apply, saving to {fname}".format(**locals()))
58 print("patch did not apply, saving to {fname}".format(**locals()))
58 print("edit {fname} until `cat {fname} | git apply --check` succeeds".format(**locals()))
59 print("edit {fname} until `cat {fname} | git apply --check` succeeds".format(**locals()))
59 print("then run tools/backport_pr.py {num} again".format(**locals()))
60 print("then run tools/backport_pr.py {num} again".format(**locals()))
60 if not os.path.exists(fname):
61 if not os.path.exists(fname):
61 with open(fname, 'wb') as f:
62 with open(fname, 'wb') as f:
62 f.write(patch)
63 f.write(patch)
63 return 1
64 return 1
64
65
65 p = Popen(['git', 'apply'], stdin=PIPE)
66 p = Popen(['git', 'apply'], stdin=PIPE)
66 a,b = p.communicate(patch)
67 a,b = p.communicate(patch)
67
68
68 commit = Popen(['git', 'commit', '-a', '-m', msg])
69 commit = Popen(['git', 'commit', '-a', '-m', msg])
69 commit.communicate()
70 commit.communicate()
70 if commit.returncode:
71 if commit.returncode:
71 print("commit failed!")
72 print("commit failed!")
72 return 1
73 return 1
73 else:
74 else:
74 print("PR #%i applied, with msg:" % num)
75 print("PR #%i applied, with msg:" % num)
75 print()
76 print()
76 print(msg)
77 print(msg)
77 print()
78 print()
78
79
79 if branch != current_branch:
80 if branch != current_branch:
80 check_call(['git', 'checkout', current_branch])
81 check_call(['git', 'checkout', current_branch])
81
82
82 return 0
83 return 0
83
84
84 if __name__ == '__main__':
85 if __name__ == '__main__':
85 if len(sys.argv) < 3:
86 if len(sys.argv) < 3:
86 print(__doc__)
87 print(__doc__)
87 sys.exit(1)
88 sys.exit(1)
88
89
89 sys.exit(backport_pr(sys.argv[1], int(sys.argv[2])))
90 sys.exit(backport_pr(sys.argv[1], int(sys.argv[2])))
General Comments 0
You need to be logged in to leave comments. Login now