diff options
author | James Laska <jlaska@redhat.com> | 2011-03-24 16:34:35 -0400 |
---|---|---|
committer | James Laska <jlaska@redhat.com> | 2011-03-24 16:34:35 -0400 |
commit | 731cc4fbc20c5709031c99c14c41abbce5589a56 (patch) | |
tree | 8568e5381539e5a96838dc5adc478fcfbc11059f | |
download | scripts-731cc4fbc20c5709031c99c14c41abbce5589a56.tar.gz scripts-731cc4fbc20c5709031c99c14c41abbce5589a56.tar.xz scripts-731cc4fbc20c5709031c99c14c41abbce5589a56.zip |
Add python blocker bug -> wiki script
-rwxr-xr-x | update-blocker-wiki | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/update-blocker-wiki b/update-blocker-wiki new file mode 100755 index 0000000..5ff268d --- /dev/null +++ b/update-blocker-wiki @@ -0,0 +1,263 @@ +#!/usr/bin/python + +import os +import sys +import bugzilla +import locale +import optparse +import getpass + +from simplemediawiki import MediaWiki + +BUG_STATUS = ['NEW', 'ASSIGNED', 'ON_DEV', 'MODIFIED', 'POST', 'ON_QA', 'FAILS_QA', + 'PASSES_QA', 'REOPENED', 'VERIFIED', 'RELEASE_PENDING'] + +# Blocker query values +BLOCKER_ACCEPTED = {'status_whiteboard': 'AcceptedBlocker', + 'status_whiteboard_type': 'anywords'} +BLOCKER_PROPOSED = {'status_whiteboard': 'AcceptedBlocker RejectedBlocker', + 'status_whiteboard_type': 'nowords'} + +# NTH query values +NTH_ACCEPTED = {'status_whiteboard': 'AcceptedNTH', + 'status_whiteboard_type': 'anywords'} +NTH_PROPOSED = {'status_whiteboard': 'AcceptedNTH RejectedNTH', + 'status_whiteboard_type': 'nowords'} + +# UTF8 helper +def to_encoding(ustring): + if isinstance(ustring, basestring): + if isinstance(ustring, unicode): + return ustring.encode(locale.getpreferredencoding(), 'replace') + return ustring + return u'' + +# Display list of bugs, organized by components +def display_bugs_by_component(bugs_by_component): + + buf = '' + components = sorted(bugs_by_component.keys()) + for component in components: + buf += '=== %s ===\n' % component + # sorted list + bugs = sorted(bugs_by_component.get(component,[])) + for b in bugs: + b = bugs_by_id[b] + buf += '* [https://bugzilla.redhat.com/%s %s] (%s) - %s\n' % (b.bug_id, b.bug_id, b.bug_status, b.short_desc) + return buf + +def parse_args(): + '''Set up the option parser''' + parser = optparse.OptionParser(usage="%prog [options] <action> [options]") + parser.add_option('-v', '--verbose', action='store_true', + default=False, help='Enable verbosity') + parser.add_option('--hotdog', action='store_true', + default=False, help='Enable hot dog (default: %default)') + + # Required args + parser.add_option('--blocker', action='store', + default=None, help='Blocker tracking bug number') + parser.add_option('--nth', action='store', + default=None, help='Nice-to-Have tracking bug number') + parser.add_option('-n', '--name', action='store', + default='Current_Release_Blockers', + help='Wiki page name to save results') + parser.add_option('-u', '--user', action='store', + default=None, help='Mediawiki username') + parser.add_option('-p', '--passwd', action='store', + default=None, help='Mediawiki password') + + (opts, args) = parser.parse_args() + + # sanitize username + if opts.user is None and sys.stdin.isatty(): + opts.user = raw_input('Enter mediawiki username: ') + if opts.user is None: + parser.error('Must provide a valid username') + # sanitize password + if opts.passwd is None and sys.stdin.isatty(): + opts.passwd = getpass.getpass('Enter mediawiki password: ') + if opts.passwd is None: + parser.error('Must provide a valid password') + + # sanitize blocker number + if opts.blocker is None: + opts.blocker = raw_input('Enter Blocker bug number: ') + if opts.blocker is None: + parser.error('Must provide a blocker bug number') + # sanitize nth number + if opts.nth is None: + opts.nth = raw_input('Enter Nice-to-have bug number: ') + if opts.nth is None: + parser.error('Must provide a nice-to-have bug number') + + return opts + +if __name__ == '__main__': + + opts = parse_args() + + # Connect to bugzilla + bz = bugzilla.RHBugzilla3(url='https://bugzilla.redhat.com/xmlrpc.cgi') + + # Get a list of accepted blocker bugs + if opts.verbose: print 'Querying accepted blocker bugs ...' + q = {'bug_status': BUG_STATUS, + 'value0-0-0': opts.blocker, + 'type0-0-0': 'substring', + 'field0-0-0': 'blocked'} + q.update(BLOCKER_ACCEPTED) + accepted_blockers = bz.query(q) + + # Get a list of proposed blocker bugs + if opts.verbose: print 'Querying proposed blocker bugs ...' + q = {'bug_status': BUG_STATUS, + 'value0-0-0': opts.blocker, + 'type0-0-0': 'substring', + 'field0-0-0': 'blocked'} + q.update(BLOCKER_PROPOSED) + proposed_blockers = bz.query(q) + + # Get a list of accepted NTH bugs + if opts.verbose: print 'Querying accepted nice-to-have bugs ...' + q = {'bug_status': BUG_STATUS, + 'value0-0-0': opts.nth, + 'type0-0-0': 'substring', + 'field0-0-0': 'blocked'} + q.update(NTH_ACCEPTED) + accepted_nths = bz.query(q) + + # Get a list of proposed NTH bugs + if opts.verbose: print 'Querying proposed nice-to-have bugs ...' + q = {'bug_status': BUG_STATUS, + 'value0-0-0': opts.nth, + 'type0-0-0': 'substring', + 'field0-0-0': 'blocked'} + q.update(NTH_PROPOSED) + proposed_nths = bz.query(q) + + # Organize bugs for later reference + if opts.verbose: print 'Organizing bugs ...' + bugs_by_id = dict() + + # walk accepted blockers + accepted_blocker_by_component = dict() + for b in accepted_blockers: + if not accepted_blocker_by_component.has_key(b.component): + accepted_blocker_by_component[b.component] = list() + accepted_blocker_by_component[b.component].append(b.bug_id) + bugs_by_id[b.bug_id] = b + + # walk proposed blockers + proposed_blocker_by_component = dict() + for b in proposed_blockers: + if not proposed_blocker_by_component.has_key(b.component): + proposed_blocker_by_component[b.component] = list() + proposed_blocker_by_component[b.component].append(b.bug_id) + bugs_by_id[b.bug_id] = b + + # walk accepted nths + accepted_nth_by_component = dict() + for b in accepted_nths: + if not accepted_nth_by_component.has_key(b.component): + accepted_nth_by_component[b.component] = list() + accepted_nth_by_component[b.component].append(b.bug_id) + bugs_by_id[b.bug_id] = b + + # walk proposed nths + proposed_nth_by_component = dict() + for b in proposed_nths: + if not proposed_nth_by_component.has_key(b.component): + proposed_nth_by_component[b.component] = list() + proposed_nth_by_component[b.component].append(b.bug_id) + bugs_by_id[b.bug_id] = b + + # Generate page content + page_content = '' + + # Start with the dog + if opts.hotdog: + page_content += '[[File:Hotdog.gif|right]]' + else: + page_content += '[[File:F{{FedoraVersionNumber|next}}_anaconda_center.png|right]]' + + # Display approved blockers + page_content += ''' +== Approved Blockers == +The following list of bugs are approved blockers that must be resolved. + +''' + # sorted list of approved bugs + page_content += display_bugs_by_component(accepted_blocker_by_component) + + # Display proposed blockers + page_content += ''' +== Proposed Blockers == +The following list of bugs are not yet approved to block the release. For guidance on reviewing the following bugs, refer to [[QA:SOP_blocker_bug_process]]. + +''' + # sorted list of proposed bugs + page_content += display_bugs_by_component(proposed_blocker_by_component) + + # Display approved nths + page_content += ''' +== Approved NICE-TO-HAVE == +The following list of bugs are approved nths that must be resolved. + +''' + # sorted list of approved bugs + page_content += display_bugs_by_component(accepted_nth_by_component) + + # Display proposed nths + page_content += ''' +== Proposed NICE-TO-HAVE == +The following list of bugs are not yet approved to block the release. For guidance on reviewing the following bugs, refer to [[QA:SOP_nth_bug_process]]. + +''' + # sorted list of proposed bugs + page_content += display_bugs_by_component(proposed_nth_by_component) + + + # Create mediawiki handle + if opts.verbose: print 'Connecting to mediawiki ...' + wiki = MediaWiki('https://fedoraproject.org/w/api.php') + + # Login to the wiki + if not wiki.login(opts.user, opts.passwd): + print "Error: invalid username or password" + sys.exit(1) + + # Get an edit token + q = dict(action='query', + prop='info', + intoken='edit', + titles=opts.name) + response = wiki.call(q) + pages = [v for k,v in response.get('query', {}).get('pages',{}).items()] + edit_token = list() + if pages: + edit_token = pages[0] + + # Make the wiki edit + q = dict(action='edit', + token=edit_token.get('edittoken',''), + starttimestamp=edit_token.get('starttimestamp',''), + summary='scripted update brought to you by python-simplemediawiki', + text=to_encoding(u'%s' % page_content), + title=opts.name) + response = wiki.call(q) + + # {'edit': {'captcha': {'mime': 'text/plain', 'type': 'simple', 'id': '674992674', 'question': '78 - 6'}, 'result': 'Failure'}} + + if response.get('edit',{}).get('result','').lower() == 'failure': + # Is a captcha required? + captcha = response.get('edit', {}).get('captcha', False) + if captcha: + q.update(dict(captchaid=captcha.get('id'), + captchaword=eval(captcha.get('question')))) + response = wiki.call(q) + if response.get('result','').lower() == 'failure': + print "Failed to update '%s'\n%s" % (q.get('title'), response) + sys.exit(1) + print "Updated '%s'" % q.get('title') + sys.exit(0) |