def _get_bugzilla_history(email, all_comments=False): """ Query the bugzilla for all bugs to which the provided email is either assigned or cc'ed. Then for each bug found, print the latest comment from this user (if any). :arg email, the email address used in the bugzilla and for which we are searching for activities. :arg all_comments, boolean to display all the comments made by this person on the bugzilla. """ from bugzilla.rhbugzilla import RHBugzilla bzclient = RHBugzilla(url='https://bugzilla.redhat.com/xmlrpc.cgi') log.debug('Querying bugzilla for email: {0}'.format(email)) print("Bugzilla activity") bugbz = bzclient.query({ 'emailtype1': 'substring', 'emailcc1': True, 'emailassigned_to1': True, 'query_format': 'advanced', 'order': 'Last Change', 'bug_status': ['ASSIGNED', 'NEW', 'NEEDINFO'], 'email1': email }) # Retrieve the information about this user user = bzclient.getuser(email) print(' {0} bugs assigned, cc or on which {1}({2}) commented'.format( len(bugbz), email, user.userid)) bugbz.reverse() print(' Last comment on the most recent ticket on bugzilla:') ids = [bug.bug_id for bug in bugbz] for bug in list(bzclient.getbugs(ids)): log.debug(bug.bug_id) if sys.version_info[0] >= 3: user_coms = list( filter(lambda com: com["creator_id"] == user.userid, bug.longdescs)) else: user_coms = filter(lambda com: com["creator_id"] == user.userid, bug.longdescs) if user_coms: last_com = user_coms[-1] converted = datetime.datetime.strptime(last_com['time'].value, "%Y%m%dT%H:%M:%S") print(u' #{0} {1} {2}'.format(bug.bug_id, converted.strftime('%Y-%m-%d'), last_com['creator'])) if not all_comments: break
def get_filed_bugs(tracking_bug): """Query bugzilla if given bug has already been filed Keyword arguments: product -- bugzilla product (usually Fedora) component -- component (package) to file bug against version -- component version to file bug for (usually rawhide for Fedora) summary -- short bug summary """ query_data = {'blocks': tracking_bug} bzurl = 'https://bugzilla.redhat.com' bzclient = RHBugzilla(url="%s/xmlrpc.cgi" % bzurl) return bzclient.query(query_data)
def report_failure(product, component, version, summary, comment, logs): """This function files a new bugzilla bug for component with given arguments Keyword arguments: product -- bugzilla product (usually Fedora) component -- component (package) to file bug against version -- component version to file bug for (usually rawhide for Fedora) summary -- short bug summary comment -- first comment describing the bug in more detail logs -- list of the log file to attach to the bug report """ data = { 'product': product, 'component': component, 'version': version, 'short_desc': summary, 'comment': comment, 'blocks': tracking_bug, 'rep_platform': 'Unspecified', 'bug_severity': 'unspecified', 'op_sys': 'Unspecified', 'bug_file_loc': '', 'priority': 'unspecified', } bzurl = 'https://bugzilla.redhat.com' bzclient = RHBugzilla(url="%s/xmlrpc.cgi" % bzurl) try: print 'Creating the bug report' bug = bzclient.createbug(**data) #print "Running bzcreate: %s" % data bug.refresh() print bug for log in logs: name = log.rsplit('/', 1)[-1] response = urllib2.urlopen(log) fp = tempfile.TemporaryFile() fp.write(response.read()) fp.seek(0) try: print 'Attaching file %s to the ticket' % name attid = bzclient.attachfile( bug.id, fp, name, content_type='text/plain') except Fault, ex: print ex finally: fp.close()
def _get_bugzilla_history(email, all_comments=False): """ Query the bugzilla for all bugs to which the provided email is either assigned or cc'ed. Then for each bug found, print the latest comment from this user (if any). :arg email, the email address used in the bugzilla and for which we are searching for activities. :arg all_comments, boolean to display all the comments made by this person on the bugzilla. """ from bugzilla.rhbugzilla import RHBugzilla bzclient = RHBugzilla(url='https://bugzilla.redhat.com/xmlrpc.cgi') log.debug('Querying bugzilla for email: {0}'.format(email)) print("Bugzilla activity") bugbz = bzclient.query({ 'emailtype1': 'substring', 'emailcc1': True, 'emailassigned_to1': True, 'query_format': 'advanced', 'order': 'Last Change', 'bug_status': ['ASSIGNED', 'NEW', 'NEEDINFO'], 'email1': email }) print(' {0} bugs assigned, cc or on which {1} commented'.format( len(bugbz), email)) # Retrieve the information about this user user = bzclient.getuser(email) bugbz.reverse() print('Last comment on the most recent ticket on bugzilla:') ids = [bug.bug_id for bug in bugbz] for bug in bzclient.getbugs(ids): log.debug(bug.bug_id) user_coms = filter(lambda com: com["creator_id"] == user.userid, bug.longdescs) if user_coms: last_com = user_coms[-1] converted = datetime.datetime.strptime(last_com['time'].value, "%Y%m%dT%H:%M:%S") print(u' #{0} {1} {2}'.format(bug.bug_id, converted.strftime('%Y-%m-%d'), last_com['author'])) if not all_comments: break
def get_bugzilla_connection(user, password): """ Return the Bugzilla connection. :param user: The username to connect with :type user: basestring :param password: The password to connect with :type password: basestring :return: An instantiated Bugzilla connection object. """ return RHBugzilla(url='%s/xmlrpc.cgi' % BUGZILLA_URL, user=user, password=password)
# Copyright Red Hat, Inc. 2013 # # This work is licensed under the terms of the GNU GPL, version 2 or later. # See the COPYING file in the top-level directory. # ''' Unit tests for building update dictionaries with 'bugzilla modify' ''' import unittest from bugzilla.rhbugzilla import RHBugzilla import tests rhbz = RHBugzilla(cookiefile=None) class ModifyTest(unittest.TestCase): maxDiff = None bz = rhbz def assertDictEqual(self, *args, **kwargs): # EPEL5 back compat if hasattr(unittest.TestCase, "assertDictEqual"): return unittest.TestCase.assertDictEqual(self, *args, **kwargs) return self.assertEqual(*args, **kwargs) def clicomm(self, argstr, out, flagsout=None, wbout=None): comm = "bugzilla modify --test-return-result 123456 224466 " + argstr
import os import re try: from urllib2 import urlopen except: from urllib.request import urlopen from bugzilla.rhbugzilla import RHBugzilla # Let's import template stuff from jinja2 import Template import mwclient __version__ = "0.2.1" bzclient = RHBugzilla( url="https://bugzilla.redhat.com/xmlrpc.cgi", cookiefile=None ) # So the bugzilla module has some way to complain logging.basicConfig() logger = logging.getLogger("bugzilla") # logger.setLevel(logging.DEBUG) RETRIES = 2 class MediaWikiException(Exception): """ MediaWikiException class. Exception class generated when something has gone wrong while querying the MediaWiki instance of the project. """
def main(): config = ConfigParser.ConfigParser() config.read(os.environ['REDMINE_BUGZILLA_CONF']) username = config.get('bugzilla', 'username') password = config.get('bugzilla', 'password') key = config.get('redmine', 'key') redmine = get_redmine_connection(key) BZ = get_bugzilla_connection(username, password) redmine_issues = [issue for issue in redmine.issue.filter(query_id=24)] non_closed_bug_with_ext_tracker = BUGZILLA_URL + '/buglist.cgi?bug_status=NEW&' \ 'bug_status=ASSIGNED&bug_status=POST&bug_status=MODIFIED&bug_status=ON_DEV&' \ 'bug_status=ON_QA&bug_status=VERIFIED&bug_status=RELEASE_PENDING&' \ 'columnlist=priority%2Cbug_severity%2Cbug_status%2Cshort_desc%2Cchangeddate%2C' \ 'component%2Ctarget_release%2Cassigned_to%2Creporter&f1=external_bugzilla.url&' \ 'list_id=3309842&o1=substring&query_format=advanced&v1=pulp.plan.io' bugzilla_bugs = BZ.query(RHBugzilla.url_to_query(non_closed_bug_with_ext_tracker)) links_issues_record = '' ext_bug_record = '' for issue in redmine_issues: for custom_field in issue.custom_fields.resources: if custom_field['name'] == 'Bugzilla': if custom_field['value'] == '': continue bug = BZ.getbug(int(custom_field['value'])) links_back = False for external_bug in bug.external_bugs: if external_bug['type']['description'] == 'Pulp Redmine' and \ external_bug['ext_bz_bug_id'] == str(issue.id): add_cc_list_to_bugzilla_bug(bug) ext_params = {} if external_bug['ext_description'] != issue.subject: ext_params['ext_description'] = issue.subject if external_bug['ext_status'] != issue.status.name: ext_params['ext_status'] = issue.status.name if external_bug['ext_priority'] != issue.priority.name: ext_params['ext_priority'] = issue.priority.name if len(ext_params.keys()) > 0: ext_bug_record += 'Bugzilla bug %s updated from upstream bug %s with ' \ '%s\n' % (bug.id, issue.id, ext_params) ext_params['ids'] = external_bug['id'] BZ.update_external_tracker(**ext_params) if 'ext_status' in ext_params: bug.addcomment( 'The Pulp upstream bug status is at %s. Updating the external ' 'tracker on this bug.' % issue.status.name) if 'ext_priority' in ext_params: bug.addcomment( 'The Pulp upstream bug priority is at %s. Updating the ' 'external tracker on this bug.' % issue.priority.name) # Remove the bug list gotten via search so we don't examine it again when # bugzilla_bugs are iterated through bug_in_search_index_to_remove = None for i, bug_in_search in enumerate(bugzilla_bugs): if bug_in_search.id == bug.id: bug_in_search_index_to_remove = i break if bug_in_search_index_to_remove is not None: bugzilla_bugs.pop(bug_in_search_index_to_remove) links_back = True if not links_back: links_issues_record += 'Redmine #%s -> Bugzilla %s, but Bugzilla %s does not ' \ 'link back\n' % (issue.id, bug.id, bug.id) for bug in bugzilla_bugs: for external_bug in bug.external_bugs: if external_bug['type']['description'] == 'Pulp Redmine': add_cc_list_to_bugzilla_bug(bug) issue_id = external_bug['ext_bz_bug_id'] issue = redmine.issue.get(issue_id) links_back = False for custom_field in issue.custom_fields.resources: if custom_field['name'] == 'Bugzilla': try: if int(custom_field['value']) == bug.id: links_back = True except KeyError: # If value isn't present this field is not linking back so continue continue except ValueError: # If value is present but empty this field is not linking back continue if not links_back: links_issues_record += 'Bugzilla #%s -> Redmine %s, but Redmine %s does ' \ 'not link back\n' % (bug.id, issue.id, issue.id) if ext_bug_record != '': print '\nBugzilla Updates From Upstream' print '------------------------------' print ext_bug_record if links_issues_record != '': print '\nLink Issues' print '-----------' print links_issues_record # Raise an exception so the job fails and Jenkins will send e-mail raise RuntimeError('Upstream/Downstream Link issues are detected')
import argparse import datetime import json import logging import os import re import urllib2 import xmlrpclib from bugzilla.rhbugzilla import RHBugzilla import fedora.client from kitchen.text.converters import to_bytes # Let's import template stuff from jinja2 import Template __version__ = '0.1.1' bzclient = RHBugzilla(url='https://bugzilla.redhat.com/xmlrpc.cgi', cookiefile=None, tokenfile=None) # So the bugzilla module has some way to complain logging.basicConfig() logger = logging.getLogger('bugzilla') #logger.setLevel(logging.DEBUG) RETRIES = 2 class MediaWikiException(Exception): """ MediaWikiException class. Exception class generated when something has gone wrong while querying the MediaWiki instance of the project. """ pass
def _load_bug(self, bug_id): bugzilla = RHBugzilla(url="https://bugzilla.redhat.com/xmlrpc.cgi") return bugzilla.getbug(bug_id, include_fields=["id", "flags"])
def main(): config = ConfigParser.ConfigParser() config.read(os.environ["REDMINE_BUGZILLA_CONF"]) username = config.get("bugzilla", "username") password = config.get("bugzilla", "password") key = config.get("redmine", "key") redmine = get_redmine_connection(key) BZ = get_bugzilla_connection(username, password) redmine_issues = [issue for issue in redmine.issue.filter(query_id=24)] non_closed_bug_with_ext_tracker = ( BUGZILLA_URL + "/buglist.cgi?bug_status=NEW&" "bug_status=ASSIGNED&bug_status=POST&bug_status=MODIFIED&bug_status=ON_DEV&" "bug_status=ON_QA&bug_status=VERIFIED&bug_status=RELEASE_PENDING&" "columnlist=priority%2Cbug_severity%2Cbug_status%2Cshort_desc%2Cchangeddate%2C" "component%2Ctarget_release%2Cassigned_to%2Creporter&f1=external_bugzilla.url&" "list_id=3309842&o1=substring&query_format=advanced&v1=pulp.plan.io" ) bugzilla_bugs = BZ.query(RHBugzilla.url_to_query(non_closed_bug_with_ext_tracker)) links_issues_record = "" ext_bug_record = "" downstream_state_issue_record = "" downstream_changes = "" for issue in redmine_issues: for custom_field in issue.custom_fields.resources: if custom_field["name"] == "Bugzillas": if custom_field["value"] == "": continue for bug_id in [int(id_str) for id_str in custom_field["value"].split(",")]: links_back = False try: bug = BZ.getbug(bug_id) except xmlrpclib.Fault as e: if e.faultCode == 102: print "Bugzilla %s could not be accessed." % bug_id continue else: raise for external_bug in bug.external_bugs: if external_bug["type"]["description"] == "Pulp Redmine" and external_bug[ "ext_bz_bug_id" ] == str(issue.id): add_cc_list_to_bugzilla_bug(bug) ext_params = {} if external_bug["ext_description"] != issue.subject: ext_params["ext_description"] = issue.subject if external_bug["ext_status"] != issue.status.name: ext_params["ext_status"] = issue.status.name if external_bug["ext_priority"] != issue.priority.name: ext_params["ext_priority"] = issue.priority.name if len(ext_params.keys()) > 0: ext_bug_record += "Bugzilla bug %s updated from upstream bug %s " "with %s\n" % ( bug.id, issue.id, ext_params, ) ext_params["ids"] = external_bug["id"] BZ.update_external_tracker(**ext_params) if "ext_status" in ext_params: bug.addcomment( "The Pulp upstream bug status is at %s. Updating the " "external tracker on this bug." % issue.status.name ) if "ext_priority" in ext_params: bug.addcomment( "The Pulp upstream bug priority is at %s. Updating the " "external tracker on this bug." % issue.priority.name ) downstream_POST_plus = [ "POST", "MODIFIED", "ON_QA", "VERIFIED", "RELEASE_PENDING", "CLOSED", ] upstream_POST_minus = ["NEW", "ASSIGNED", "POST"] if bug.status in downstream_POST_plus and issue.status.name in upstream_POST_minus: msg = "The downstream bug %s is at POST+ but the upstream bug %s " "at POST-.\n" % ( bug.id, issue.id, ) downstream_state_issue_record += msg links_back = True transition_to_post = [] for external_bug in bug.external_bugs: if external_bug["type"]["description"] == "Foreman Issue Tracker": # If the bug has an external foreman issue, don't transition the BZ transition_to_post.append(False) if external_bug["type"]["description"] == "Pulp Redmine": if bug.status in ["NEW", "ASSIGNED"]: if external_bug["ext_status"] in [ "MODIFIED", "ON_QA", "VERIFIED", "CLOSED - CURRENTRELEASE", ]: transition_to_post.append(True) else: transition_to_post.append(False) if not links_back: links_issues_record += "Redmine #%s -> Bugzilla %s, but Bugzilla %s does " "not link back\n" % ( issue.id, bug.id, bug.id, ) if len(transition_to_post) > 0 and all(transition_to_post): msg = "All upstream Pulp bugs are at MODIFIED+. Moving this bug to POST." bug.setstatus("POST", msg) downstream_changes += "Bugzilla %s was transitioned to POST\n" % bug.id for bug in bugzilla_bugs: for external_bug in bug.external_bugs: if external_bug["type"]["description"] == "Pulp Redmine": add_cc_list_to_bugzilla_bug(bug) issue_id = external_bug["ext_bz_bug_id"] issue = redmine.issue.get(issue_id) links_back = False for custom_field in issue.custom_fields.resources: if custom_field["name"] == "Bugzillas" and custom_field["value"]: bug_list = [int(id_str) for id_str in custom_field["value"].split(",")] for bug_id in bug_list: try: if bug_id == bug.id: links_back = True except KeyError: # If value isn't present this field is not linking back continue except ValueError: # If value is present but empty this field is not linking back continue if not links_back: links_issues_record += "Bugzilla #%s -> Redmine %s, but Redmine %s does " "not link back\n" % ( bug.id, issue.id, issue.id, ) if ext_bug_record != "": print "\nBugzilla Updates From Upstream" print "------------------------------" print ext_bug_record if downstream_changes != "": print "\nBugzilla Transitions to POST" print "----------------------------" print downstream_changes if links_issues_record != "": print "\nLink Issues" print "-----------" print links_issues_record if downstream_state_issue_record != "": print "\nDownstream State Issues" print "-----------------------" print downstream_state_issue_record if links_issues_record != "" or downstream_state_issue_record != "": # Raise an exception so the job fails and Jenkins will send e-mail raise RuntimeError("We need a human here")
def main(): config = ConfigParser.ConfigParser() config.read(os.environ['REDMINE_BUGZILLA_CONF']) username = config.get('bugzilla', 'username') password = config.get('bugzilla', 'password') key = config.get('redmine', 'key') redmine = get_redmine_connection(key) BZ = get_bugzilla_connection(username, password) bug_with_ext_tracker = \ BUGZILLA_URL + '/buglist.cgi?classification=Red%20Hat&columnlist=priority%2Cbug_severity' \ '%2Cbug_status%2Cshort_desc%2Cchangeddate%2Ccomponent%2Ctarget_release%2C' \ 'assigned_to%2Creporter&f1=external_bugzilla.url&list_id=7254713&o1=' \ 'substring&product=Red%20Hat%20Satellite%206&query_format=advanced&' \ 'resolution=---&resolution=CURRENTRELEASE&resolution=RAWHIDE&resolution=' \ 'ERRATA&resolution=NEXTRELEASE&resolution=INSUFFICIENT_DATA&resolution=EOL' \ '&v1=pulp.plan.io' bugzilla_bugs = BZ.query(RHBugzilla.url_to_query(bug_with_ext_tracker)) upstream_issues_checked_memo = {} # A memo allowing us to never check an issue twice all_BZs = set() BZs_fixed_by_version = defaultdict(lambda : set()) for i, bug in enumerate(bugzilla_bugs): # if i == 20: # break all_BZs.add(bug.id) bug = BZ.getbug(bug.id) upstream_associated_issue_numbers = [] for external_bug in bug.external_bugs: if external_bug['type']['description'] == 'Pulp Redmine': upstream_associated_issue_numbers.append(int(external_bug['ext_bz_bug_id'])) upstream_fixed_versions_for_bz = [] for upstream_id in upstream_associated_issue_numbers: # Check the memo to see if we already know the fix version if upstream_id in upstream_fixed_versions_for_bz: if upstream_fixed_versions_for_bz[upstream_id] != u'': # We already know the upstream version with the fix available upstream_fixed_versions_for_bz.append( upstream_fixed_versions_for_bz[upstream_id] ) all_BZs.add(bug.id) # The memo info was used so we can move on to the next upstream issue to check continue upstream_issue = redmine.issue.get(upstream_id) # Issues in 'External' are not actual issues so they should be ignored if upstream_issue.project.name == u'External': # Never check an upstream issue twice upstream_issues_checked_memo[upstream_id] = u'' continue platform_release_field = upstream_issue.custom_fields.get(4) # 'Platform Release' field # Never check an upstream issue twice upstream_issues_checked_memo[upstream_id] = platform_release_field[u'value'] if platform_release_field[u'value'] != u'': upstream_fixed_versions_for_bz.append(platform_release_field[u'value']) all_BZs.add(bug.id) if upstream_fixed_versions_for_bz != []: fix_in = max([semantic_version.Version(v) for v in upstream_fixed_versions_for_bz]) BZs_fixed_by_version[str(fix_in)].add(bug.id) upstream_versions = [semantic_version.Version(v) for v in BZs_fixed_by_version.keys()] upstream_versions.sort() # Ensure in increasing order BZs_fixed_list = [BZs_fixed_by_version[str(v)] for v in upstream_versions] for i in range(1, len(BZs_fixed_list)): BZs_fixed_list[i] = BZs_fixed_list[i - 1] | BZs_fixed_list[i] for i, version in enumerate(upstream_versions): BZs_fixed_by_version[str(version)] = BZs_fixed_list[i] BZs_missing_by_version = {} for version, bugs in BZs_fixed_by_version.iteritems(): BZs_missing_by_version[version] = all_BZs - BZs_fixed_by_version[version] minimum_version = semantic_version.Version(MINIMUM_VERSION) for v in upstream_versions: if v < minimum_version: continue bugs_in_this_version = BZs_missing_by_version[str(v)] print '%s, %s, https://bugzilla.redhat.com/buglist.cgi?quicksearch=%s' % ( v, len(bugs_in_this_version), ','.join([str(i) for i in bugs_in_this_version]) )
def _load_bug(self, bug_id): bugzilla = RHBugzilla(url='https://bugzilla.redhat.com/xmlrpc.cgi') return bugzilla.getbug(bug_id, include_fields=['id', 'flags'])
def do_acl(args): ''' Retrieves the ACLs of a package from pkgdb. ''' LOG.info("package : {0}".format(args.package)) LOG.info("branch : {0}".format(args.branch)) #LOG.info("approve : {0}".format(args.approve)) bzclient = RHBugzilla(url=RH_BZ_API) if args.branch == 'all': args.branch = None output = pkgdbclient.get_package(args.package, branches=args.branch) print 'Fedora Package Database -- {0}'.format(args.package) if output['packages']: print output['packages'][0]['package']['summary'] if args.extra: # print the number of opened bugs LOG.debug("Query bugzilla") bugbz = bzclient.query( {'bug_status': ['NEW', 'ASSIGNED', 'NEEDINFO'], 'component': args.package}) print "{0} bugs open (new, assigned, needinfo)".format(len(bugbz)) for pkg in output['packages']: if pkg['collection']['status'] == 'EOL': continue owner = pkg['point_of_contact'] if owner == 'orphan': owner = RED + owner + RESET # Retrieve ACL information print "\n{0}{1}{2}{3}Point of Contact:{4}{5}".rstrip().format( RED + BOLD, pkg['collection']['branchname'], RESET, " " * (8 - len(pkg['collection']['branchname'])), " " * 5, owner) # print header of the table tmp = " " * 24 for acl in ["watchbugzilla", "watchcommits", "commit", "approveacls"]: tmp = tmp + acl + " " * (16 - len(acl)) print tmp.rstrip() # print ACL information print "{0}ACLs:".format(" " * 8) acls = _get_acls_info(pkg['acls']) for user in acls: tmp = " " * 10 + user tmp = tmp + " " * (24 - len(tmp)) for acl_title in ["watchbugzilla", "watchcommits", "commit", "approveacls"]: #print '\n', acl_title if acl_title in acls[user]: aclout = acls[user][acl_title] tmp = tmp + aclout + " " * (16 - len(aclout)) else: tmp = tmp + aclout + " " * 8 if tmp is not None and tmp.strip() != "": print tmp # print the last build if args.extra: tag = pkg['collection']['branchname'] get_last_build(pkg['package']['name'], tag)
import logging import os import pickle import pymongo #import requests_cache import sys import time from datetime import datetime from pprint import pprint from bugzilla.rhbugzilla import RHBugzilla from xmlrpc.client import DateTime #requests_cache.install_cache('.bz_cache') bugzilla = RHBugzilla(url='https://bugzilla.redhat.com/xmlrpc.cgi', user=os.environ.get('BUGZILLA_USERNAME'), password=os.environ.get('BUGZILLA_PASSWORD')) #query = bugzilla.build_query(product='Ansible Tower') #tickets = bugzilla.query(query) ''' (Epdb) ticket = tickets[0] (Epdb) pp ticket.getcomments()[0].keys() ['count', 'author', 'text', 'creator', 'creation_time', 'bug_id', 'creator_id', 'time',
def main(key, last_change_time=None): logger.info(f"Starting process: last_change_time={last_change_time}") bz_api = RHBugzilla(url=URL, api_key=key) bz_bsu = BZBugScoreUpdater(bz_api) bz_bsu.perform_bug_score_updates(last_change_time)
import argparse import datetime import json import logging import os import re import urllib2 import xmlrpclib from bugzilla.rhbugzilla import RHBugzilla import fedora.client from kitchen.text.converters import to_bytes # Let's import template stuff from jinja2 import Template __version__ = '0.1.1' bzclient = RHBugzilla(url='https://bugzilla.redhat.com/xmlrpc.cgi', cookiefile=None) # So the bugzilla module has some way to complain logging.basicConfig() logger = logging.getLogger('bugzilla') #logger.setLevel(logging.DEBUG) RETRIES = 2 class MediaWikiException(Exception): """ MediaWikiException class. Exception class generated when something has gone wrong while querying the MediaWiki instance of the project. """ pass
def main(): config = ConfigParser.ConfigParser() config.read(os.environ['REDMINE_BUGZILLA_CONF']) username = config.get('bugzilla', 'username') password = config.get('bugzilla', 'password') key = config.get('redmine', 'key') redmine = get_redmine_connection(key) BZ = get_bugzilla_connection(username, password) redmine_issues = [issue for issue in redmine.issue.filter(query_id=24)] non_closed_bug_with_ext_tracker = BUGZILLA_URL + '/buglist.cgi?bug_status=NEW&' \ 'bug_status=ASSIGNED&bug_status=POST&bug_status=MODIFIED&bug_status=ON_DEV&' \ 'bug_status=ON_QA&bug_status=VERIFIED&bug_status=RELEASE_PENDING&' \ 'columnlist=priority%2Cbug_severity%2Cbug_status%2Cshort_desc%2Cchangeddate%2C' \ 'component%2Ctarget_release%2Cassigned_to%2Creporter&f1=external_bugzilla.url&' \ 'list_id=3309842&o1=substring&query_format=advanced&v1=pulp.plan.io' bugzilla_bugs = BZ.query(RHBugzilla.url_to_query(non_closed_bug_with_ext_tracker)) links_issues_record = '' ext_bug_record = '' downstream_state_issue_record = '' downstream_changes = '' for issue in redmine_issues: for custom_field in issue.custom_fields.resources: if custom_field['name'] == 'Bugzillas': if custom_field['value'] == '': continue for bug_id in [int(id_str) for id_str in custom_field['value'].split(',')]: links_back = False try: bug = BZ.getbug(bug_id) except xmlrpclib.Fault as e: if e.faultCode == 102: print 'Bugzilla %s could not be accessed.' % bug_id continue else: raise transition_to_post = [] for external_bug in bug.external_bugs: if external_bug['type']['description'] == 'Foreman Issue Tracker': # If the bug has an external foreman issue, don't transition the BZ transition_to_post.append(False) if external_bug['type']['description'] == 'Pulp Redmine' and \ external_bug['ext_bz_bug_id'] == str(issue.id): add_cc_list_to_bugzilla_bug(bug) ext_params = {} if external_bug['ext_description'] != issue.subject: ext_params['ext_description'] = issue.subject if external_bug['ext_status'] != issue.status.name: ext_params['ext_status'] = issue.status.name if external_bug['ext_priority'] != issue.priority.name: ext_params['ext_priority'] = issue.priority.name if len(ext_params.keys()) > 0: ext_bug_record += 'Bugzilla bug %s updated from upstream bug %s ' \ 'with %s\n' % (bug.id, issue.id, ext_params) ext_params['ids'] = external_bug['id'] BZ.update_external_tracker(**ext_params) if 'ext_status' in ext_params: bug.addcomment( 'The Pulp upstream bug status is at %s. Updating the ' 'external tracker on this bug.' % issue.status.name) if 'ext_priority' in ext_params: bug.addcomment( 'The Pulp upstream bug priority is at %s. Updating the ' 'external tracker on this bug.' % issue.priority.name) if bug.status in ['NEW', 'ASSIGNED']: if issue.status.name in ['MODIFIED', 'ON_QA', 'VERIFIED', 'CLOSED - CURRENTRELEASE']: transition_to_post.append(True) else: transition_to_post.append(False) downstream_POST_plus = ['POST', 'MODIFIED', 'ON_QA', 'VERIFIED', 'RELEASE_PENDING', 'CLOSED'] upstream_POST_minus = ['NEW', 'ASSIGNED', 'POST'] if bug.status in downstream_POST_plus and \ issue.status.name in upstream_POST_minus: msg = 'The downstream bug %s is at POST+ but the upstream bug %s ' \ 'at POST-.\n' % (bug.id, issue.id) downstream_state_issue_record += msg links_back = True if not links_back: links_issues_record += 'Redmine #%s -> Bugzilla %s, but Bugzilla %s does ' \ 'not link back\n' % (issue.id, bug.id, bug.id) if len(transition_to_post) > 0 and all(transition_to_post): msg = 'All upstream Pulp bugs are at MODIFIED+. Moving this bug to POST.' bug.setstatus('POST', msg) downstream_changes += 'Bugzilla %s was transitioned to POST\n' % bug.id for bug in bugzilla_bugs: for external_bug in bug.external_bugs: if external_bug['type']['description'] == 'Pulp Redmine': add_cc_list_to_bugzilla_bug(bug) issue_id = external_bug['ext_bz_bug_id'] issue = redmine.issue.get(issue_id) links_back = False for custom_field in issue.custom_fields.resources: if custom_field['name'] == 'Bugzillas' and custom_field['value']: bug_list = [int(id_str) for id_str in custom_field['value'].split(',')] for bug_id in bug_list: try: if bug_id == bug.id: links_back = True except KeyError: # If value isn't present this field is not linking back continue except ValueError: # If value is present but empty this field is not linking back continue if not links_back: links_issues_record += 'Bugzilla #%s -> Redmine %s, but Redmine %s does ' \ 'not link back\n' % (bug.id, issue.id, issue.id) if ext_bug_record != '': print '\nBugzilla Updates From Upstream' print '------------------------------' print ext_bug_record if downstream_changes != '': print '\nBugzilla Transitions to POST' print '----------------------------' print downstream_changes if links_issues_record != '': print '\nLink Issues' print '-----------' print links_issues_record if downstream_state_issue_record != '': print '\nDownstream State Issues' print '-----------------------' print downstream_state_issue_record if links_issues_record != '' or downstream_state_issue_record != '': # Raise an exception so the job fails and Jenkins will send e-mail raise RuntimeError('We need a human here')
def main(): config = ConfigParser.ConfigParser() config.read(os.environ['REDMINE_BUGZILLA_CONF']) username = config.get('bugzilla', 'username') password = config.get('bugzilla', 'password') key = config.get('redmine', 'key') redmine = get_redmine_connection(key) BZ = get_bugzilla_connection(username, password) bug_with_ext_tracker = \ BUGZILLA_URL + '/buglist.cgi?classification=Red%20Hat&columnlist=priority%2Cbug_severity' \ '%2Cbug_status%2Cshort_desc%2Cchangeddate%2Ccomponent%2Ctarget_release%2C' \ 'assigned_to%2Creporter&f1=external_bugzilla.url&list_id=7254713&o1=' \ 'substring&product=Red%20Hat%20Satellite%206&query_format=advanced&' \ 'resolution=---&resolution=CURRENTRELEASE&resolution=RAWHIDE&resolution=' \ 'ERRATA&resolution=NEXTRELEASE&resolution=INSUFFICIENT_DATA&resolution=EOL' \ '&v1=pulp.plan.io' bugzilla_bugs = BZ.query(RHBugzilla.url_to_query(bug_with_ext_tracker)) upstream_issues_checked_memo = { } # A memo allowing us to never check an issue twice all_BZs = set() BZs_fixed_by_version = defaultdict(lambda: set()) for i, bug in enumerate(bugzilla_bugs): # if i == 20: # break all_BZs.add(bug.id) bug = BZ.getbug(bug.id) upstream_associated_issue_numbers = [] for external_bug in bug.external_bugs: if external_bug['type']['description'] == 'Pulp Redmine': upstream_associated_issue_numbers.append( int(external_bug['ext_bz_bug_id'])) upstream_fixed_versions_for_bz = [] for upstream_id in upstream_associated_issue_numbers: # Check the memo to see if we already know the fix version if upstream_id in upstream_fixed_versions_for_bz: if upstream_fixed_versions_for_bz[upstream_id] != u'': # We already know the upstream version with the fix available upstream_fixed_versions_for_bz.append( upstream_fixed_versions_for_bz[upstream_id]) all_BZs.add(bug.id) # The memo info was used so we can move on to the next upstream issue to check continue upstream_issue = redmine.issue.get(upstream_id) # Issues in 'External' are not actual issues so they should be ignored if upstream_issue.project.name == u'External': # Never check an upstream issue twice upstream_issues_checked_memo[upstream_id] = u'' continue platform_release_field = upstream_issue.custom_fields.get( 4) # 'Platform Release' field # Never check an upstream issue twice upstream_issues_checked_memo[upstream_id] = platform_release_field[ u'value'] if platform_release_field[u'value'] != u'': upstream_fixed_versions_for_bz.append( platform_release_field[u'value']) all_BZs.add(bug.id) if upstream_fixed_versions_for_bz != []: fix_in = max([ semantic_version.Version(v) for v in upstream_fixed_versions_for_bz ]) BZs_fixed_by_version[str(fix_in)].add(bug.id) upstream_versions = [ semantic_version.Version(v) for v in BZs_fixed_by_version.keys() ] upstream_versions.sort() # Ensure in increasing order BZs_fixed_list = [BZs_fixed_by_version[str(v)] for v in upstream_versions] for i in range(1, len(BZs_fixed_list)): BZs_fixed_list[i] = BZs_fixed_list[i - 1] | BZs_fixed_list[i] for i, version in enumerate(upstream_versions): BZs_fixed_by_version[str(version)] = BZs_fixed_list[i] BZs_missing_by_version = {} for version, bugs in BZs_fixed_by_version.iteritems(): BZs_missing_by_version[ version] = all_BZs - BZs_fixed_by_version[version] minimum_version = semantic_version.Version(MINIMUM_VERSION) for v in upstream_versions: if v < minimum_version: continue bugs_in_this_version = BZs_missing_by_version[str(v)] print '%s, %s, https://bugzilla.redhat.com/buglist.cgi?quicksearch=%s' % ( v, len(bugs_in_this_version), ','.join( [str(i) for i in bugs_in_this_version]))
def main(): config = ConfigParser.ConfigParser() config.read(os.environ['REDMINE_BUGZILLA_CONF']) username = config.get('bugzilla', 'username') password = config.get('bugzilla', 'password') key = config.get('redmine', 'key') redmine = get_redmine_connection(key) BZ = get_bugzilla_connection(username, password) redmine_issues = [issue for issue in redmine.issue.filter(query_id=24)] non_closed_bug_with_ext_tracker = BUGZILLA_URL + '/buglist.cgi?bug_status=NEW&' \ 'bug_status=ASSIGNED&bug_status=POST&bug_status=MODIFIED&bug_status=ON_DEV&' \ 'bug_status=ON_QA&bug_status=VERIFIED&bug_status=RELEASE_PENDING&' \ 'columnlist=priority%2Cbug_severity%2Cbug_status%2Cshort_desc%2Cchangeddate%2C' \ 'component%2Ctarget_release%2Cassigned_to%2Creporter&f1=external_bugzilla.url&' \ 'list_id=3309842&o1=substring&query_format=advanced&v1=pulp.plan.io' bugzilla_bugs = BZ.query( RHBugzilla.url_to_query(non_closed_bug_with_ext_tracker)) links_issues_record = '' ext_bug_record = '' downstream_state_issue_record = '' downstream_changes = '' new_failed_qa_record = '' failed_qa_bugzillas = [] for issue in redmine_issues: for custom_field in issue.custom_fields.resources: if custom_field['name'] == 'Bugzillas': if custom_field['value'] == '': continue for bug_id in [ int(id_str) for id_str in custom_field['value'].split(',') ]: links_back = False if bug_id in failed_qa_bugzillas: continue try: bug = BZ.getbug(bug_id) except xmlrpclib.Fault as e: if e.faultCode == 102: print 'Bugzilla %s could not be accessed.' % bug_id continue else: raise for external_bug in bug.external_bugs: if external_bug['type']['description'] == 'Pulp Redmine' and \ external_bug['ext_bz_bug_id'] == str(issue.id): add_cc_list_to_bugzilla_bug(bug) ext_params = {} if external_bug['ext_description'] != issue.subject: ext_params['ext_description'] = issue.subject if external_bug['ext_status'] != issue.status.name: ext_params['ext_status'] = issue.status.name if external_bug[ 'ext_priority'] != issue.priority.name: ext_params[ 'ext_priority'] = issue.priority.name if len(ext_params.keys()) > 0: ext_bug_record += 'Bugzilla bug %s updated from upstream bug %s ' \ 'with %s\n' % (bug.id, issue.id, ext_params) ext_params['ids'] = external_bug['id'] BZ.update_external_tracker(**ext_params) if 'ext_status' in ext_params: bug.addcomment( 'The Pulp upstream bug status is at %s. Updating the ' 'external tracker on this bug.' % issue.status.name) if 'ext_priority' in ext_params: bug.addcomment( 'The Pulp upstream bug priority is at %s. Updating the ' 'external tracker on this bug.' % issue.priority.name) downstream_POST_plus = [ 'POST', 'MODIFIED', 'ON_QA', 'VERIFIED', 'RELEASE_PENDING', 'CLOSED' ] downstream_ACCEPTABLE_resolution = [ 'NOTABUG', 'WONTFIX', 'DEFERRED', 'WORKSFORME' ] upstream_POST_minus = ['NEW', 'ASSIGNED', 'POST'] if bug.status in downstream_POST_plus and \ issue.status.name in upstream_POST_minus: if bug.resolution not in downstream_ACCEPTABLE_resolution: msg = 'The downstream bug %s is at POST+ but the upstream ' \ 'bug %s at POST-.\n' % (bug.id, issue.id) downstream_state_issue_record += msg links_back = True transition_to_post = [] for external_bug in bug.external_bugs: if external_bug['type'][ 'description'] == 'Foreman Issue Tracker': # If the bug has an external foreman issue, don't transition the BZ transition_to_post.append(False) if external_bug['type'][ 'description'] == 'Pulp Redmine': if bug.status in ['NEW', 'ASSIGNED']: if external_bug['ext_status'] in [ 'MODIFIED', 'ON_QA', 'VERIFIED', 'CLOSED - CURRENTRELEASE' ]: if 'FailedQA' in bug.cf_verified: needinfo = True external_bug_id = external_bug[ 'ext_bz_bug_id'] redmine_issue = redmine.issue.get( external_bug_id) redmine_user_id = redmine_issue.assigned_to.id needinfo_email = redmine.user.get( redmine_user_id).mail msg = "Bugzilla %s failed QA. Needinfo is set for %s." % \ (bug.id, needinfo_email) for flag in bug.flags: if flag['name'] == 'needinfo' and \ flag['requestee'] == needinfo_email: needinfo = False if needinfo: BZ.update_flags( bug.id, [{ "name": "needinfo", "status": "?", "requestee": needinfo_email, "new": True }]) bug.addcomment("Requesting needsinfo from upstream " \ "developer %s because the 'FailedQA' " \ "flag is set." % needinfo_email) new_failed_qa_record += "%s\n" % msg print msg failed_qa_bugzillas.append(bug.id) else: transition_to_post.append(True) else: transition_to_post.append(False) if not links_back: links_issues_record += 'Redmine #%s -> Bugzilla %s, but Bugzilla %s does ' \ 'not link back\n' % (issue.id, bug.id, bug.id) if len(transition_to_post) > 0 and all(transition_to_post): msg = 'All upstream Pulp bugs are at MODIFIED+. Moving this bug to POST.' bug.setstatus('POST', msg) downstream_changes += 'Bugzilla %s was transitioned to POST\n' % bug.id for bug in bugzilla_bugs: for external_bug in bug.external_bugs: if external_bug['type']['description'] == 'Pulp Redmine': add_cc_list_to_bugzilla_bug(bug) issue_id = external_bug['ext_bz_bug_id'] issue = redmine.issue.get(issue_id) links_back = False for custom_field in issue.custom_fields.resources: if custom_field['name'] == 'Bugzillas' and custom_field[ 'value']: bug_list = [ int(id_str) for id_str in custom_field['value'].split(',') ] for bug_id in bug_list: try: if bug_id == bug.id: links_back = True except KeyError: # If value isn't present this field is not linking back continue except ValueError: # If value is present but empty this field is not linking back continue if not links_back: links_issues_record += 'Bugzilla #%s -> Redmine %s, but Redmine %s does ' \ 'not link back\n' % (bug.id, issue.id, issue.id) if ext_bug_record != '': print '\nBugzilla Updates From Upstream' print '------------------------------' print ext_bug_record if downstream_changes != '': print '\nBugzilla Transitions to POST' print '----------------------------' print downstream_changes if links_issues_record != '': print '\nLink Issues' print '-----------' print links_issues_record if downstream_state_issue_record != '': print '\nDownstream State Issues' print '-----------------------' print downstream_state_issue_record if new_failed_qa_record != '': print '\nNew Bugzillas That Failed QA' print '----------------------------' print new_failed_qa_record if links_issues_record != '' or downstream_state_issue_record != '' or new_failed_qa_record: # Raise an exception so the job fails and Jenkins will send e-mail raise RuntimeError('We need a human here')