587.2.1
by Curtis Hovey
Added an outline of a script that can explain why a branch cannot be merged. |
1 |
#!/usr/bin/python
|
2 |
||
3 |
from __future__ import print_function |
|
4 |
||
5 |
from argparse import ArgumentParser |
|
587.2.2
by Curtis Hovey
Updated script to return a code and reason why a pull rquest can or cannot be tested. |
6 |
import json |
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
7 |
import sys |
587.2.2
by Curtis Hovey
Updated script to return a code and reason why a pull rquest can or cannot be tested. |
8 |
import urllib2 |
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
9 |
|
940.1.22
by Curtis Hovey
Updated per review. |
10 |
from launchpadlib.launchpad import ( |
11 |
Launchpad, |
|
12 |
uris, |
|
13 |
)
|
|
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
14 |
|
15 |
||
16 |
BUG_STATUSES = [ |
|
17 |
'Incomplete', 'Confirmed', 'Triaged', 'In Progress', 'Fix Committed'] |
|
18 |
BUG_IMPORTANCES = ['Critical'] |
|
19 |
BUG_TAGS = ['blocker'] |
|
587.2.5
by Curtis Hovey
Added test for get_reason. |
20 |
GH_COMMENTS = 'https://api.github.com/repos/juju/juju/issues/{}/comments' |
587.2.2
by Curtis Hovey
Updated script to return a code and reason why a pull rquest can or cannot be tested. |
21 |
|
22 |
||
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
23 |
def get_json(uri): |
940.1.16
by Curtis Hovey
Added doc strings. |
24 |
"""Return the json dict response for the uri request."""
|
660.1.1
by Martin Packman
Bypass caches when checking blocking bugs against launchpad |
25 |
request = urllib2.Request(uri, headers={ |
26 |
"Cache-Control": "max-age=0, must-revalidate", |
|
27 |
})
|
|
940.3.1
by Martin Packman
Make the check_blockers script more suitable for human usage |
28 |
response = urllib2.urlopen(request) |
29 |
data = response.read() |
|
30 |
if response.getcode() == 200 and data: |
|
587.2.2
by Curtis Hovey
Updated script to return a code and reason why a pull rquest can or cannot be tested. |
31 |
return json.loads(data) |
587.2.1
by Curtis Hovey
Added an outline of a script that can explain why a branch cannot be merged. |
32 |
return None |
33 |
||
34 |
||
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
35 |
def get_lp(script_name, credentials_file=None): |
36 |
"""Return an LP API client."""
|
|
940.1.22
by Curtis Hovey
Updated per review. |
37 |
lp_args = dict() |
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
38 |
if credentials_file: |
39 |
lp_args['credentials_file'] = credentials_file |
|
940.1.22
by Curtis Hovey
Updated per review. |
40 |
lp = Launchpad.login_with( |
41 |
script_name, service_root=uris.LPNET_SERVICE_ROOT, |
|
42 |
version='devel', **lp_args) |
|
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
43 |
return lp |
44 |
||
45 |
||
587.2.3
by Curtis Hovey
Added some basic tests to confirm URLs are created for Lp bug checking. |
46 |
def parse_args(args=None): |
47 |
parser = ArgumentParser('Check if a branch is blocked from landing') |
|
940.1.4
by Curtis Hovey
Added credentials=None to get_json() and make -c universal. |
48 |
parser.add_argument( |
940.1.6
by Curtis Hovey
Use credentials if Lp data needs to change. |
49 |
"-c", "--credentials-file", default=None, |
940.1.4
by Curtis Hovey
Added credentials=None to get_json() and make -c universal. |
50 |
help="Launchpad credentials file.") |
940.1.1
by Curtis Hovey
Move th check blockers args into a "check" subcommand. |
51 |
subparsers = parser.add_subparsers(help='sub-command help', dest="command") |
52 |
check_parser = subparsers.add_parser( |
|
53 |
'check', help='Check if merges are blocked for a branch.') |
|
940.3.2
by Martin Packman
Merge trunk to resolve conflicts with check_blockers update subcommand |
54 |
check_parser.add_argument('branch', default='master', nargs='?', |
953.3.9
by Nate Finch
more code review changes |
55 |
help='The branch to merge into.') |
940.3.2
by Martin Packman
Merge trunk to resolve conflicts with check_blockers update subcommand |
56 |
check_parser.add_argument('pull_request', default=None, nargs='?', |
953.3.9
by Nate Finch
more code review changes |
57 |
help='The pull request to be merged') |
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
58 |
update_parser = subparsers.add_parser( |
940.1.3
by Curtis Hovey
Added update command. |
59 |
'update', help='Update blocking for a branch that passed CI.') |
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
60 |
update_parser.add_argument( |
61 |
'-d', '--dry-run', action='store_true', default=False, |
|
62 |
help='Do not make changes.') |
|
63 |
update_parser.add_argument('branch', help='The branch that passed.') |
|
64 |
update_parser.add_argument( |
|
940.1.3
by Curtis Hovey
Added update command. |
65 |
'build', help='The build-revision build number.') |
587.2.3
by Curtis Hovey
Added some basic tests to confirm URLs are created for Lp bug checking. |
66 |
return parser.parse_args(args) |
67 |
||
68 |
||
940.1.11
by Curtis Hovey
Pass lp to get_lp_bugs and update_bugs. |
69 |
def get_lp_bugs(lp, branch, with_ci=False): |
940.1.16
by Curtis Hovey
Added doc strings. |
70 |
"""Return a dict of blocker critical bug tasks for the branch."""
|
587.2.2
by Curtis Hovey
Updated script to return a code and reason why a pull rquest can or cannot be tested. |
71 |
bugs = {} |
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
72 |
project = lp.projects['juju-core'] |
940.1.11
by Curtis Hovey
Pass lp to get_lp_bugs and update_bugs. |
73 |
if branch == 'master': |
940.1.20
by Curtis Hovey
Restore comment. |
74 |
# Lp implicitly assigns bugs to trunk, which is not a series query.
|
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
75 |
target = project |
76 |
else: |
|
940.1.11
by Curtis Hovey
Pass lp to get_lp_bugs and update_bugs. |
77 |
target = project.getSeries(name=branch) |
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
78 |
if not target: |
936.1.1
by Curtis Hovey
Look up supported branches and include incomplete and confirmed as bugs blockers. |
79 |
return bugs |
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
80 |
if with_ci: |
81 |
bug_tags = BUG_TAGS + ['ci'] |
|
587.2.2
by Curtis Hovey
Updated script to return a code and reason why a pull rquest can or cannot be tested. |
82 |
else: |
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
83 |
bug_tags = BUG_TAGS |
84 |
bug_tasks = target.searchTasks( |
|
85 |
status=BUG_STATUSES, importance=BUG_IMPORTANCES, |
|
86 |
tags=bug_tags, tags_combinator='All') |
|
87 |
for bug_task in bug_tasks: |
|
940.1.17
by Curtis Hovey
Add a message about why the task is Fix Released. |
88 |
# Avoid an extra network call to get the bug report.
|
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
89 |
bug_id = bug_task.self_link.split('/')[-1] |
90 |
bugs[bug_id] = bug_task |
|
587.2.2
by Curtis Hovey
Updated script to return a code and reason why a pull rquest can or cannot be tested. |
91 |
return bugs |
92 |
||
93 |
||
94 |
def get_reason(bugs, args): |
|
940.1.16
by Curtis Hovey
Added doc strings. |
95 |
"""Return the success code and reason why the branch can be merged."""
|
587.2.2
by Curtis Hovey
Updated script to return a code and reason why a pull rquest can or cannot be tested. |
96 |
if not bugs: |
97 |
return 0, 'No blocking bugs' |
|
609
by Curtis Hovey
Do note require __ on both ends of fixes-xxxx because github thinks the underscores are markdown. |
98 |
fixes_ids = ['fixes-{}'.format(bug_id) for bug_id in bugs] |
940.3.1
by Martin Packman
Make the check_blockers script more suitable for human usage |
99 |
if args.pull_request is None: |
100 |
return 1, 'Blocked waiting on {}'.format(fixes_ids) |
|
587.2.5
by Curtis Hovey
Added test for get_reason. |
101 |
uri = GH_COMMENTS.format(args.pull_request) |
587.2.2
by Curtis Hovey
Updated script to return a code and reason why a pull rquest can or cannot be tested. |
102 |
comments = get_json(uri) |
940.3.1
by Martin Packman
Make the check_blockers script more suitable for human usage |
103 |
if comments is not None: |
587.2.2
by Curtis Hovey
Updated script to return a code and reason why a pull rquest can or cannot be tested. |
104 |
for comment in comments: |
595
by Curtis Hovey
Ignore comments by jujubot because its explanation about what need fixing |
105 |
user = comment['user'] |
606
by Curtis Hovey
Reject comments with Juju bot in them because that implies a reply or someone |
106 |
if user['login'] == 'jujubot' or 'Juju bot' in comment['body']: |
595
by Curtis Hovey
Ignore comments by jujubot because its explanation about what need fixing |
107 |
continue
|
607
by Curtis Hovey
Added __JFDI__ to allow engineers to force a merge. |
108 |
if '__JFDI__' in comment['body']: |
109 |
return 0, 'Engineer says JFDI' |
|
587.2.2
by Curtis Hovey
Updated script to return a code and reason why a pull rquest can or cannot be tested. |
110 |
for fid in fixes_ids: |
111 |
if fid in comment['body']: |
|
112 |
return 0, 'Matches {}'.format(fid) |
|
113 |
else: |
|
114 |
return 1, 'Does not match {}'.format(fixes_ids) |
|
115 |
return 1, 'Could not get {} comments from github'.format(args.pull_request) |
|
587.2.1
by Curtis Hovey
Added an outline of a script that can explain why a branch cannot be merged. |
116 |
|
117 |
||
940.1.17
by Curtis Hovey
Add a message about why the task is Fix Released. |
118 |
def update_bugs(bugs, branch, build, dry_run=False): |
940.1.21
by Curtis Hovey
Fix status name. |
119 |
"""Update the critical blocker+ci bugs for the branch to Fix Released."""
|
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
120 |
changes = [] |
940.1.13
by Curtis Hovey
Added tests for update_bugs. |
121 |
for bug_id, bug_task in bugs.items(): |
940.1.18
by Curtis Hovey
Revise text formatting based on the bugtask.title format. |
122 |
changes.append('Updated %s' % bug_task.title) |
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
123 |
bug_task.status = 'Fix Released' |
124 |
if not dry_run: |
|
125 |
bug_task.lp_save() |
|
940.1.17
by Curtis Hovey
Add a message about why the task is Fix Released. |
126 |
subject = 'Fix Released in juju-core %s' % branch |
127 |
content = ( |
|
128 |
'Juju-CI verified that this issue is %s:\n' |
|
129 |
' http://reports.vapour.ws/releases/%s' % (subject, build)) |
|
130 |
bug_task.bug.newMessage(subject=subject, content=content) |
|
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
131 |
changes = '\n'.join(changes) |
132 |
return 0, changes |
|
940.1.9
by Curtis Hovey
Added test for check_blockers.py main call chain. |
133 |
|
134 |
||
135 |
def main(argv): |
|
136 |
args = parse_args(argv) |
|
940.1.11
by Curtis Hovey
Pass lp to get_lp_bugs and update_bugs. |
137 |
lp = get_lp('check_blockers', credentials_file=args.credentials_file) |
940.1.2
by Curtis Hovey
Op name is "check". |
138 |
if args.command == 'check': |
940.1.11
by Curtis Hovey
Pass lp to get_lp_bugs and update_bugs. |
139 |
bugs = get_lp_bugs(lp, args.branch, with_ci=False) |
940.1.1
by Curtis Hovey
Move th check blockers args into a "check" subcommand. |
140 |
code, reason = get_reason(bugs, args) |
141 |
print(reason) |
|
940.1.4
by Curtis Hovey
Added credentials=None to get_json() and make -c universal. |
142 |
elif args.command == 'update': |
940.1.11
by Curtis Hovey
Pass lp to get_lp_bugs and update_bugs. |
143 |
bugs = get_lp_bugs(lp, args.branch, with_ci=True) |
940.1.17
by Curtis Hovey
Add a message about why the task is Fix Released. |
144 |
code, changes = update_bugs( |
145 |
bugs, args.branch, args.build, dry_run=args.dry_run) |
|
940.1.10
by Curtis Hovey
Switch to launchpadlib (very invasive) |
146 |
print(changes) |
587.2.1
by Curtis Hovey
Added an outline of a script that can explain why a branch cannot be merged. |
147 |
return code |
148 |
||
149 |
||
150 |
if __name__ == '__main__': |
|
940.1.9
by Curtis Hovey
Added test for check_blockers.py main call chain. |
151 |
sys.exit(main(sys.argv[1:])) |