| |
@@ -1,937 +0,0 @@
|
| |
- #!/usr/bin/python -t
|
| |
- VERSION = "1.0"
|
| |
-
|
| |
- # Unfortunately pkgdb can't tell us when we stop accepting branches for the
|
| |
- # oldest supported release, so this needs updating manually.
|
| |
- OBSOLETE_BRANCH='f20'
|
| |
-
|
| |
- # A bug for testing new types of badly formatted requests exists:
|
| |
- # https://bugzilla.redhat.com/show_bug.cgi?id=622067
|
| |
-
|
| |
- # A bug for testing flags, primarily by limburgher, also exists:
|
| |
- # https://bugzilla.redhat.com/show_bug.cgi?id=837840
|
| |
-
|
| |
- # TODO:
|
| |
- # Display last linked spec file.
|
| |
- # Download (and process?) last linked srpm
|
| |
-
|
| |
- # Checks to add:
|
| |
- # Package and/or branch already exists in pkgdb.
|
| |
- # Catch common misspellings?
|
| |
-
|
| |
- import bugzilla
|
| |
- import getpass
|
| |
- import logging
|
| |
- import operator
|
| |
- import os
|
| |
- import re
|
| |
- import readline
|
| |
- import sys
|
| |
- import subprocess
|
| |
- import tempfile
|
| |
- import time
|
| |
- import webbrowser
|
| |
- import socket
|
| |
- from configobj import ConfigObj, flatten_errors
|
| |
- from fedora.client import AccountSystem, AuthError, AppError
|
| |
- from pkgdb2client import PkgDB, PkgDBException
|
| |
- from optparse import OptionParser
|
| |
- from validate import Validator
|
| |
-
|
| |
- import fedora_cert
|
| |
- import pkgdb2client
|
| |
-
|
| |
- # Red Hat's bugzilla, Fedora's FAS
|
| |
- url = 'https://bugzilla.redhat.com/xmlrpc.cgi'
|
| |
- fasurl = 'https://admin.fedoraproject.org/accounts/'
|
| |
-
|
| |
- # Users who indicated that they're OK with EPEL branches. Some request that
|
| |
- # they be made comaintainers.
|
| |
- # Taken from https://fedoraproject.org/wiki/EPEL/ContributorStatusNo
|
| |
- epel_ok = ['abompard', 'athimm', 'corsepiu', 'ecik', 'faucamp', 'konradm',
|
| |
- 'monnerat', 'mtasaka', 'nim', 'rafalzaq', 'rineau', 'rstrode',
|
| |
- 'sgrubb', 'shishz', 'terjeros', 'zkota']
|
| |
- epel_ok_comaint = ['alexlan', 'guidograzioli', 'jwrdegoede', 'kkofler',
|
| |
- 'mebourne', 'overholt', 'pgordon', 'rishi', 'snirkel']
|
| |
-
|
| |
- PAGER = os.environ.get('PAGER') or '/usr/bin/less'
|
| |
- EDITOR = os.environ.get('EDITOR') or '/bin/vi'
|
| |
-
|
| |
- logging.basicConfig()
|
| |
- PKGDBLOG = logging.getLogger("pkgdb2client")
|
| |
- LOG = logging.getLogger("process-git-requests")
|
| |
-
|
| |
- # Override a method in xmlrpclib so it doesn't blow up when getting crap data
|
| |
- # from Red Hat's bugzilla.
|
| |
- # Bugfixes seem to have rendered this unnecessary
|
| |
- #def _decode(data, encoding, is8bit=re.compile("[\x80-\xff]").search):
|
| |
- # # decode non-ascii string (if possible)
|
| |
- # if unicode and encoding and is8bit(data):
|
| |
- # data = unicode(data, encoding, 'replace')
|
| |
- # return data
|
| |
- #xmlrpclib._decode = _decode
|
| |
-
|
| |
- def clear():
|
| |
- #os.system('clearl)
|
| |
- print "\n============================================================\n"
|
| |
-
|
| |
- def parse_commandline():
|
| |
- usage = 'usage: %prog [options]'
|
| |
- parser = OptionParser(usage)
|
| |
-
|
| |
- try:
|
| |
- default_user = fedora_cert.read_user_cert()
|
| |
- except fedora_cert.fedora_cert_error:
|
| |
- default_user = getpass.getuser()
|
| |
-
|
| |
- parser.add_option('--url', dest='url',
|
| |
- help='bugzilla URL to query',
|
| |
- default=url)
|
| |
- parser.add_option('--pkghost',
|
| |
- help='Hostname of the machine where branches must be created',
|
| |
- dest='pkghost',
|
| |
- default='pkgs.fedoraproject.org')
|
| |
- parser.add_option('--pkghostlocal',
|
| |
- help='Local hostname of the machine where branches must be created',
|
| |
- dest='pkghostlocal',
|
| |
- default='pkgs01.phx2.fedoraproject.org')
|
| |
- parser.add_option('-u', '--user',
|
| |
- help='Username for PackageDB connection',
|
| |
- dest='user',
|
| |
- default=default_user)
|
| |
- parser.add_option('--verbose',
|
| |
- action='store_true',
|
| |
- dest='verbose',
|
| |
- default=False,
|
| |
- help='Outputs more information (less than debug though)')
|
| |
- parser.add_option('--debug',
|
| |
- action='store_true',
|
| |
- dest='debug',
|
| |
- default=False,
|
| |
- help='Turn on some debugging statements')
|
| |
-
|
| |
- (options, args) = parser.parse_args()
|
| |
- return options
|
| |
-
|
| |
- def parse_pkgdb_config():
|
| |
- vldtr = Validator()
|
| |
- # configspec to validate types and set defaults
|
| |
- configspec = '''
|
| |
- [global]
|
| |
- pkgdb.url = string(default = 'https://admin.fedoraproject.org/pkgdb')
|
| |
- pkgdb.retries = integer(default = 5)
|
| |
- pkgdb.knowngroups = list(default = list())
|
| |
- '''.splitlines()
|
| |
-
|
| |
- cfg = ConfigObj('/etc/pkgdb-client.cfg', configspec=configspec)
|
| |
- user = ConfigObj(os.path.expanduser('~/.fedora/pkgdb-client.cfg'),
|
| |
- configspec=configspec)
|
| |
- cfg.merge(user)
|
| |
- res = cfg.validate(vldtr, preserve_errors=True)
|
| |
-
|
| |
- for entry in flatten_errors(cfg, res):
|
| |
- section_list, key, error = entry
|
| |
- section_list.append(key)
|
| |
- section_string = ','.join(section_list)
|
| |
- if error == False:
|
| |
- error = 'Missing value or section.'
|
| |
- print ','.join(section_list), '=', error
|
| |
- sys.exit(1)
|
| |
-
|
| |
- cfg['global']['pkgdb.url'] = os.environ.get('PACKAGEDBURL') or cfg['global']['pkgdb.url']
|
| |
- return cfg['global']
|
| |
-
|
| |
- def encode_utf8(object, encoding='utf8', errors='replace'):
|
| |
- if isinstance(object, basestring):
|
| |
- if isinstance(object, str):
|
| |
- return unicode(object, encoding, errors)
|
| |
- else:
|
| |
- return object
|
| |
- return u''
|
| |
-
|
| |
- # Get all valid branches for a package:
|
| |
- # pkg_branches :: PkgDB -> String -> (IO) [String]
|
| |
- def pkg_branches(pkgdb, pkg):
|
| |
- LOG.info('Getting branches of package %s from pkgdb', pkg)
|
| |
- package = pkgdb.get_package(str(pkg))
|
| |
- valid_branches = filter(lambda x: x['collection']['branchname'] in branches.keys(), package['packages'])
|
| |
- return map(lambda x: x['collection']['branchname'], valid_branches)
|
| |
-
|
| |
- def add_package(pkgdb, request, bug):
|
| |
- LOG.info('Adding package %s in pkgdb', request['pkg'])
|
| |
-
|
| |
- # A nested helper function to see if a package exists or not.
|
| |
- # pkg_exists :: String -> (IO) Bool
|
| |
- def pkg_exists(pkg):
|
| |
- try:
|
| |
- pkgdb.get_package(str(pkg))
|
| |
- except PkgDBException as err:
|
| |
- LOG.debug('Error when retrieving package %s: %s', str(pkg), err)
|
| |
- # We get an error back if (at least) the package doesn't exist.
|
| |
- return False
|
| |
- return True
|
| |
-
|
| |
- for retry in range(1, config['pkgdb.retries'] + 1):
|
| |
- try:
|
| |
- if pkg_exists(request['pkg']):
|
| |
- pkgdb.update_package_poc(request['pkg'],
|
| |
- pkg_branches(pkgdb, request['pkg']),
|
| |
- request['owner'])
|
| |
- else:
|
| |
- # Note: must stringify the pkg; it blows up with unicode
|
| |
- pkgdb.create_package(
|
| |
- str(request['pkg']),
|
| |
- request['description'],
|
| |
- None,
|
| |
- 'https://bugzilla.redhat.com/%d' % bug.id,
|
| |
- 'Approved',
|
| |
- True, # TODO: Nuke this eventually?
|
| |
- request['branches'],
|
| |
- request['owner'],
|
| |
- request.get('upstream_url', ''))
|
| |
-
|
| |
- # Set comaintainer ACLs
|
| |
- for i in request['comaintainers']:
|
| |
- pkgdb.update_acl(
|
| |
- str(request['pkg']),
|
| |
- request['branches'],
|
| |
- ['watchcommits', 'watchbugzilla', 'approveacls', 'commit'],
|
| |
- 'Approved',
|
| |
- i)
|
| |
- # Set CC user
|
| |
- for i in request.get('cc_list', []):
|
| |
- pkgdb.update_acl(
|
| |
- str(request['pkg']),
|
| |
- request['branches'],
|
| |
- ['watchcommits', 'watchbugzilla'],
|
| |
- 'Approved',
|
| |
- i)
|
| |
- except AuthError, e:
|
| |
- LOG.debug('It says AuthError: %s', e)
|
| |
- if sys.stdin.isatty():
|
| |
- if retry >= config['pkgdb.retries']:
|
| |
- break
|
| |
- #pkgdb.password = getpass.getpass('PackageDB Password: ')
|
| |
- else:
|
| |
- # Don't retry if we're reading the password from stdin
|
| |
- break
|
| |
- else:
|
| |
- break
|
| |
-
|
| |
- def edit_package(pkgdb, request):
|
| |
- LOG.info('Edit package %s in pkgdb', request['pkg'])
|
| |
- for retry in range(1, config['pkgdb.retries'] + 1):
|
| |
- try:
|
| |
- for person in ([request['owner']] + request['comaintainers']):
|
| |
- pkgdb.update_acl(
|
| |
- str(request['pkg']),
|
| |
- request['newbranches'],
|
| |
- ['watchcommits', 'watchbugzilla', 'approveacls', 'commit'],
|
| |
- 'Approved',
|
| |
- person)
|
| |
- except AuthError, e:
|
| |
- if retry >= config['pkgdb.retries']:
|
| |
- break
|
| |
- #pkgdb.password = getpass.getpass('PackageDB Password: ')
|
| |
- else:
|
| |
- break
|
| |
-
|
| |
- def run_query(bz):
|
| |
- querydata = {}
|
| |
- querydata['column_list'] = ['id', 'creation_time',
|
| |
- 'assigned_to', 'reporter', 'bug_status', 'resolution',
|
| |
- 'component', 'blockedby', 'dependson', 'summary',
|
| |
- 'status_whiteboard', 'flags']
|
| |
-
|
| |
- querydata['query_format'] = 'advanced'
|
| |
- querydata['product'] = ['Fedora', 'Fedora EPEL']
|
| |
- querydata['f1'] = 'flagtypes.name'
|
| |
- querydata['o1'] = 'equals'
|
| |
- querydata['v1'] = 'fedora-cvs?'
|
| |
-
|
| |
- bugs = bz.query(querydata)
|
| |
- bugs.sort(key=operator.attrgetter('id'))
|
| |
-
|
| |
- ids = map(lambda x: x.id, bugs)
|
| |
- comments = bz._proxy.Bug.comments({"ids": ids})
|
| |
-
|
| |
- return [bugs, comments]
|
| |
-
|
| |
- def display_bug(bug, comments):
|
| |
- '''Show the complete ticket in a pager.'''
|
| |
- comment = 0
|
| |
- b = []
|
| |
- b.append('https://bugzilla.redhat.com/%d' % bug.id)
|
| |
- b.append('Bug %d - %s' % (bug.id, bug.summary))
|
| |
- b.append('Reported by: %s at %s' % (bug.reporter, bug.creation_time))
|
| |
- b.append('Assigned to: %s' % (bug.assigned_to))
|
| |
- for i in comments:
|
| |
- b.append('-'*40)
|
| |
- b.append('Comment %d by %s at %s\n' % (comment, i['author'], time.strftime('%F %T',i['time'].timetuple())))
|
| |
- b.append(i['text'])
|
| |
- b.append('')
|
| |
- comment += 1
|
| |
-
|
| |
- p = subprocess.Popen(PAGER, stdin=subprocess.PIPE)
|
| |
- p.communicate('\n'.join(b).encode('utf8'))
|
| |
-
|
| |
-
|
| |
- def edit_string(s):
|
| |
- '''Edit the contents of a string in the user's preferred editor.'''
|
| |
- (fd, f) = tempfile.mkstemp()
|
| |
- fh=os.fdopen(fd, 'w+')
|
| |
- fh.write(s)
|
| |
- fh.close()
|
| |
- p = subprocess.Popen([EDITOR, f]);
|
| |
- sts = os.waitpid(p.pid, 0)[1]
|
| |
- if not sts:
|
| |
- try:
|
| |
- fh = open(f, 'r')
|
| |
- s = fh.read()
|
| |
- finally:
|
| |
- fh.close()
|
| |
-
|
| |
- return s
|
| |
-
|
| |
-
|
| |
- def parse_prefixed_lines(s):
|
| |
- lastitem = ''
|
| |
- items = {}
|
| |
- items['Branches'] = ''
|
| |
- items['New Branches'] = ''
|
| |
- lines = s.splitlines()
|
| |
-
|
| |
- # Skip until the Request line
|
| |
- while 1:
|
| |
- if (lines[0].find('New Package CVS Request') == 0
|
| |
- or lines[0].find('New Package GIT Request') == 0
|
| |
- or lines[0].find('New Package SCM Request') == 0
|
| |
- or lines[0].find('Package Change Request') == 0):
|
| |
- break
|
| |
- lines.pop(0)
|
| |
-
|
| |
- # Skip until a line containing a colon
|
| |
- while 1:
|
| |
- if lines[0].find(':') >= 0:
|
| |
- break
|
| |
- lines.pop(0)
|
| |
-
|
| |
- # Now parse
|
| |
- while 1:
|
| |
- if not len(lines):
|
| |
- break
|
| |
-
|
| |
- line = lines.pop(0)
|
| |
- line.strip()
|
| |
- if len(line) == 0:
|
| |
- break
|
| |
-
|
| |
- pos = line.find(':')
|
| |
-
|
| |
- # Line-wrapped?
|
| |
- if pos < 0:
|
| |
- items[lastitem] += " " + line.strip()
|
| |
- continue
|
| |
-
|
| |
- lastitem = line[:pos]
|
| |
- items[lastitem] = line[pos+1:].strip()
|
| |
-
|
| |
- return items
|
| |
-
|
| |
-
|
| |
- def clean_branches(branches):
|
| |
- '''Clean up a list of branches and turn them into what pkgdb expects.'''
|
| |
- branches = branches.lower()
|
| |
- branches = re.sub(r',', ' ', branches)
|
| |
- branches = re.sub(r'devel', ' ', branches)
|
| |
- branches = re.sub(r'master', ' ', branches)
|
| |
- branches = re.sub(r'f-([1-9][0-9])', r'f\1', branches)
|
| |
- branches = re.sub(r'el-([1-6])', r'el\1', branches)
|
| |
- branches = re.sub(r'el-([7-9])', r'epel\1', branches)
|
| |
- branches = re.sub(r'epel-([1-9])', r'epel\1', branches)
|
| |
- branches = re.sub(r'epel([1-9])', r'el\1', branches)
|
| |
- branches = re.sub(r' +', ' ', branches)
|
| |
- branches = re.sub(r'el7', r'epel7', branches)
|
| |
- branches = branches.strip()
|
| |
- return branches
|
| |
-
|
| |
-
|
| |
- def clean_request(items):
|
| |
- '''Clean up various bits that can be passed in a request.'''
|
| |
- request = {}
|
| |
-
|
| |
- if not 'InitialCC' in items:
|
| |
- items['InitialCC'] = ''
|
| |
- if not 'Owners' in items:
|
| |
- items['Owners'] = ''
|
| |
- if not 'Short Description' in items:
|
| |
- items['Short Description'] = ''
|
| |
- if not 'Upstream URL' in items:
|
| |
- items['Upstream URL'] = ''
|
| |
-
|
| |
- branches = clean_branches(items['Branches'].strip())
|
| |
- branches += ' master'
|
| |
- items['Branches'] = branches
|
| |
- request['branches'] = branches.split()
|
| |
-
|
| |
- branches = clean_branches(items['New Branches'].strip())
|
| |
- items['New Branches'] = branches
|
| |
- request['newbranches'] = branches.split()
|
| |
-
|
| |
- owners = items['Owners'].strip()
|
| |
- owners = re.sub(r',', ' ', owners)
|
| |
- if len(owners):
|
| |
- request['owner'] = owners.split()[0]
|
| |
- request['comaintainers'] = owners.split()[1:]
|
| |
- else:
|
| |
- request['owner'] = ''
|
| |
- request['comaintainers'] = []
|
| |
-
|
| |
- cclist = items['InitialCC'].strip()
|
| |
- cclist = re.sub(r',', ' ', cclist)
|
| |
-
|
| |
- upstreamurl = items['Upstream URL'].strip()
|
| |
-
|
| |
- request['cc_list'] = cclist.split()
|
| |
- request['pkg'] = items['Package Name']
|
| |
- request['description'] = items['Short Description']
|
| |
- request['upstream_url'] = upstreamurl
|
| |
-
|
| |
- return request
|
| |
-
|
| |
-
|
| |
- def new_request_string(items, bug):
|
| |
- r = []
|
| |
- r.append("Bug URL: https://bugzilla.redhat.com/%d " % bug.id)
|
| |
- r.append("Bug summary: " + bug.summary)
|
| |
- r.append('')
|
| |
- r.append("New Package SCM Request")
|
| |
- r.append("=======================")
|
| |
- r.append("Package Name: " + items['Package Name'])
|
| |
- r.append("Short Description: " + items['Short Description'])
|
| |
- r.append("Upstream URL: " + items['Upstream URL'])
|
| |
- r.append("Owners: " + items['Owners'])
|
| |
- r.append("Branches: " + items['Branches'])
|
| |
- r.append("InitialCC: " + items['InitialCC'])
|
| |
- r.append('')
|
| |
- return '\n'.join(r)
|
| |
-
|
| |
-
|
| |
- def change_request_string(items, bug):
|
| |
- r = []
|
| |
- r.append("Bug URL: https://bugzilla.redhat.com/%d" % bug.id)
|
| |
- r.append("Bug summary: " + bug.summary)
|
| |
- r.append('')
|
| |
- r.append("Package Change Request")
|
| |
- r.append("======================")
|
| |
- r.append("Package Name: " + items['Package Name'])
|
| |
- r.append("Owners: " + items['Owners'])
|
| |
- r.append("New Branches: " + items['New Branches'])
|
| |
- r.append("InitialCC: " + items['InitialCC'])
|
| |
- r.append('')
|
| |
- return '\n'.join(r)
|
| |
-
|
| |
-
|
| |
- def get_pkgdb_owners(pkgdb, pkg):
|
| |
- owners = {}
|
| |
- o = ''
|
| |
- try:
|
| |
- package = pkgdb.get_package(pkg)
|
| |
- except PkgDBException, e:
|
| |
- return (owners, o)
|
| |
-
|
| |
- # This mostly duplicates a procedure above, but we need more than just
|
| |
- # the branch name :(
|
| |
- valid_branches = filter(lambda x: x['collection']['branchname'] in branches.keys(), package['packages'])
|
| |
- for i in valid_branches:
|
| |
- branch = i['collection']['branchname']
|
| |
- owners[branch] = {}
|
| |
- owners[branch]['primary'] = i['point_of_contact']
|
| |
-
|
| |
- # Get fas names of all people with commit access
|
| |
- # then filter out 'group::' and the POC.
|
| |
- if 'acls' in i:
|
| |
- comaint = map(lambda x: x['fas_name'], filter(lambda x: x['acl'] == 'commit', i['acls']))
|
| |
- owners[branch]['comaint'] = filter(lambda x: not x.startswith('group::') and x != i['point_of_contact'], comaint)
|
| |
- else:
|
| |
- owners[branch]['comaint'] = []
|
| |
-
|
| |
- for i in sorted(branches, reverse=True):
|
| |
- if i in owners:
|
| |
- o += "%s: %s" % (i, owners[i]['primary'])
|
| |
- if len(owners[i]['comaint']):
|
| |
- o += ' - %s' % ','.join(sorted(owners[i]['comaint']))
|
| |
- o += '\n'
|
| |
-
|
| |
- return (owners, o)
|
| |
-
|
| |
-
|
| |
- def process_no_request(bug, allcomments):
|
| |
- '''Deal with a ticket where no request was found.'''
|
| |
- while 1:
|
| |
- clear()
|
| |
- print "No SCM request found in bug %d\nhttps://bugzilla.redhat.com/%d." % (bug.id, bug.id)
|
| |
- ok = raw_input('\nWhat do? (n=Next, s=Show ticket, b=Show ticket in browser, c=Comment, q=Quit):')
|
| |
- if ok == 'c':
|
| |
- bug_comment = edit_string('')
|
| |
- print bug_comment
|
| |
- ok = raw_input("\nPost this comment to the ticket (y/n)?")
|
| |
- if ok == 'y':
|
| |
- print "Updating bugzilla..."
|
| |
- bug.addcomment(bug_comment)
|
| |
- ok = raw_input("\nClear the fedora-cvs flag (y/n)?")
|
| |
- if ok == 'y':
|
| |
- print "Clearing the flag..."
|
| |
- bug.updateflags({'fedora-cvs':'X'})
|
| |
- break
|
| |
- elif ok == 'n':
|
| |
- return True
|
| |
- elif ok == 'q':
|
| |
- return False
|
| |
- elif ok == 's':
|
| |
- print
|
| |
- display_bug(bug, allcomments)
|
| |
- elif ok == 'b':
|
| |
- webbrowser.open("https://bugzilla.redhat.com/" + str(bug.id), new=1)
|
| |
- return True
|
| |
-
|
| |
-
|
| |
- def check_owner(fas, owner):
|
| |
- """Check if owner is a valid FAS account or group.
|
| |
-
|
| |
- If owner is a valid FAS account, also check if owner is a packager.
|
| |
- """
|
| |
- warnings = []
|
| |
- if owner.startswith('group::'):
|
| |
- group_name = owner[7:]
|
| |
- try:
|
| |
- group = fas.group_by_name(group_name)
|
| |
- if not group_name.endswith('-sig') and not group['group_type'] == 'pkgdb':
|
| |
- warnings.append('WARNING: "%s" is not a valid FAS group.' % group_name)
|
| |
- except AppError:
|
| |
- warnings.append('WARNING: "%s" could not be found as FAS group.' % group_name)
|
| |
- else: # Check if owner is a valid user
|
| |
- person = fas.person_by_username(owner)
|
| |
- if not 'status' in person:
|
| |
- warnings.append('WARNING: "%s" is not a valid FAS account.' % i)
|
| |
- else:
|
| |
- groups = [g['name'] for g in person.approved_memberships]
|
| |
- if not 'packager' in groups:
|
| |
- warnings.append('WARNING: "%s" is not in the packager group.' % i)
|
| |
- return warnings
|
| |
-
|
| |
-
|
| |
- def check_owners(fas, owner, comaintainers, cc_list):
|
| |
- print "Checking owners..."
|
| |
- warnings = []
|
| |
-
|
| |
- for i in [owner] + comaintainers:
|
| |
- for retry in range(1, config['pkgdb.retries'] + 1):
|
| |
- try:
|
| |
- warnings.extend(check_owner(fas, i))
|
| |
- except AuthError, e:
|
| |
- if retry >= config['pkgdb.retries']:
|
| |
- break
|
| |
- print e
|
| |
- fas.password = getpass.getpass(
|
| |
- 'FAS Password for user {}: '.format(fas.username))
|
| |
- else:
|
| |
- break
|
| |
-
|
| |
- for i in cc_list:
|
| |
- warnings.extend(check_owner(fas, i))
|
| |
-
|
| |
- return warnings
|
| |
-
|
| |
-
|
| |
- def process_new_request(bug, comment, allcomments, firstfound, pkgdb, fas, branches):
|
| |
- '''Parse a new package request, try to repair line wrapping, and do some
|
| |
- basic validity checks.'''
|
| |
- LOG.info('Processing new package requests')
|
| |
- warned = False
|
| |
- warnings = []
|
| |
- items = parse_prefixed_lines(comment['text'])
|
| |
- request = clean_request(items)
|
| |
-
|
| |
- w = check_owners(fas, request['owner'], request['comaintainers'], request['cc_list'])
|
| |
- if len(w):
|
| |
- warnings.extend(w)
|
| |
- warned = True
|
| |
-
|
| |
- if not 'Owners' in items:
|
| |
- warnings.append("WARNING: No owners provided.")
|
| |
- warned = True
|
| |
- if not firstfound:
|
| |
- warnings.append("WARNING: SCM request was not the last comment.")
|
| |
- warned = True
|
| |
- if not 'Package Name' in items:
|
| |
- warnings.append("WARNING: No package name supplied.")
|
| |
- warned = True
|
| |
- if not('Short Description' in items) or not(len(items['Short Description'])):
|
| |
- warnings.append("WARNING: No description provided.")
|
| |
- warned = True
|
| |
- if not 'Upstream URL' in items:
|
| |
- warnings.append("WARNING: No upstream URL provided.")
|
| |
- warned = True
|
| |
- for i in request['branches']:
|
| |
- if i not in branches:
|
| |
- warnings.append("WARNING: Invalid branch %s requested" % i)
|
| |
- warned = True
|
| |
- if bug.assigned_to == 'nobody@fedoraproject.org':
|
| |
- warnings.append("WARNING: Ticket is not assigned to anyone.")
|
| |
- warned = True
|
| |
-
|
| |
- frflag = bug.get_flags('fedora-review')
|
| |
- if not frflag:
|
| |
- warnings.append("WARNING: fedora-review flag not set")
|
| |
- warned = True
|
| |
- else:
|
| |
- if frflag[0]['status'] != '+':
|
| |
- warnings.append("WARNING: fedora-review flag not set to '+'")
|
| |
- warned = True
|
| |
- if frflag[0]['setter'] == bug.reporter:
|
| |
- warnings.append("WARNING: fedora-review flag set by review submitter! Verify that review was approved by reviewer!")
|
| |
- warned = True
|
| |
-
|
| |
- m=re.search('Review Request:\s+([a-zA-Z0-9_+.-]+)\s+', bug.summary, re.I)
|
| |
- if not m:
|
| |
- warnings.append("WARNING: Couldn't parse package name out of bug summary.")
|
| |
- warned = True
|
| |
- elif m.group(1) != items['Package Name']:
|
| |
- warnings.append("WARNING: Requested package name %s doesn't match bug summary %s" % (items['Package Name'], m.group(1)))
|
| |
- warned = True
|
| |
-
|
| |
- if items.get('Upstream URL', None) and not items['Upstream URL'].startswith('http://') and not items['Upstream URL'].startswith('https://'):
|
| |
- warnings.append("WARNING: Upstream URL seems to be invalid")
|
| |
- warned = True
|
| |
-
|
| |
- req_string = new_request_string(items, bug)
|
| |
- bug_comment = 'Git done (by process-git-requests).\n'
|
| |
-
|
| |
- okprompt = 'Do it (yes=Yes, n=No, e=Edit request, s=Show ticket, b=Show ticket in browser, c=Comment, q=Quit)?'
|
| |
- if warned:
|
| |
- prompt = 'Warnings present!\nDo it (a=Accept warnings, n=No, e=Edit request, s=Show ticket, b=Show ticket in browser, c=Comment, q=Quit)?'
|
| |
- else:
|
| |
- prompt = okprompt
|
| |
-
|
| |
- # We have to loop until the user accepts the request
|
| |
- while 1:
|
| |
- # We have to loop until the user enters something that works
|
| |
- while 1:
|
| |
- clear()
|
| |
- if len(warnings):
|
| |
- print '\n'.join(warnings), "\n"
|
| |
- print "Currently assigned to: %s" % bug.assigned_to
|
| |
- print req_string
|
| |
- ok = raw_input(prompt)
|
| |
- if ok == 'a':
|
| |
- prompt = okprompt
|
| |
- warned = False
|
| |
- if ok == 'c':
|
| |
- bug_comment = edit_string('')
|
| |
- print bug_comment
|
| |
- ok = raw_input("\nPost this comment to the ticket (y/n)?")
|
| |
- if ok == 'y':
|
| |
- print "Updating bugzilla..."
|
| |
- bug.addcomment(bug_comment)
|
| |
- ok = raw_input("\nClear the fedora-cvs flag (y/n)?")
|
| |
- if ok == 'y':
|
| |
- print "Clearing the flag..."
|
| |
- bug.updateflags({'fedora-cvs':'X'})
|
| |
- return (False, True)
|
| |
- elif ok == 'e':
|
| |
- req_string = edit_string(req_string)
|
| |
- items=parse_prefixed_lines(req_string)
|
| |
- request = clean_request(items)
|
| |
- req_string = new_request_string(items, bug)
|
| |
- break
|
| |
- elif ok == 'n':
|
| |
- return (False, True)
|
| |
- elif ok == 'q':
|
| |
- return (False, False)
|
| |
- elif ok == 's':
|
| |
- print
|
| |
- display_bug(bug, allcomments)
|
| |
- elif ok == 'b':
|
| |
- webbrowser.open("https://bugzilla.redhat.com/" + str(bug.id), new=1)
|
| |
- elif ok == 'yes' and not warned:
|
| |
- bug_comment = edit_string(bug_comment)
|
| |
- print '\n', bug_comment
|
| |
- ok = raw_input('Go ahead (y/n)?')
|
| |
- if ok != 'y':
|
| |
- break
|
| |
- print 'Calling pkgdb...'
|
| |
- try:
|
| |
- add_package(pkgdb, request, bug)
|
| |
- except Exception, e:
|
| |
- print "Pkgdb call failed:"
|
| |
- print e
|
| |
- raw_input('\nPress enter to continue to the next ticket.')
|
| |
- return (False, True)
|
| |
-
|
| |
- print 'Updating bugzilla...'
|
| |
- # XXX Need to handle errors here - might be done, limburgher 2012-09-05
|
| |
- try:
|
| |
- bug.updateflags({'fedora-cvs':'+'})
|
| |
- except Exception, e:
|
| |
- print "Bugzilla call failed:"
|
| |
- print e
|
| |
- raw_input('\nPress enter to continue to the next ticket.')
|
| |
- return (False, True)
|
| |
- try:
|
| |
- bug.addcomment(bug_comment)
|
| |
- except Exception, e:
|
| |
- print "Bugzilla call failed:"
|
| |
- print e
|
| |
- raw_input('\nPress enter to continue to the next ticket.')
|
| |
- return (False, True)
|
| |
-
|
| |
- return (request['pkg'], True)
|
| |
- else:
|
| |
- pass
|
| |
-
|
| |
- def process_change_request(bug, comment, allcomments, firstfound, pkgdb, branches):
|
| |
- '''Parse a change request, try to repair line wrapping, and do some
|
| |
- basic validity checks.'''
|
| |
- LOG.info('Processing new branch requests')
|
| |
- owned = False
|
| |
- warned = False
|
| |
- warnings = []
|
| |
- items = parse_prefixed_lines(comment['text'])
|
| |
- request = clean_request(items)
|
| |
- print "Looking up owners in pkgdb..."
|
| |
- (owners, owner_string) = get_pkgdb_owners(pkgdb, items['Package Name'])
|
| |
-
|
| |
- # Try to enforce EPEL branch rules
|
| |
- exists = True
|
| |
- if not len(owners):
|
| |
- warnings.append("WARNING: Package does not appear to exist in pkgdb currently.")
|
| |
- warned = True
|
| |
- exists = False
|
| |
-
|
| |
- if not len(items['New Branches']) and len(items['Branches']):
|
| |
- warnings.append("NOTE: Misformatted request; using 'Branches' instead.")
|
| |
- items['New Branches'] == items['Branches'];
|
| |
- request['newbranches'] = request['branches']
|
| |
-
|
| |
- for i in owners.keys():
|
| |
- if request['owner'] == owners[i]['primary'] or request['owner'] in owners[i]['comaint']:
|
| |
- owned = True
|
| |
- if exists and not owned and items['New Branches'].find('EL') >= 0 and owners['devel']['primary'] in epel_ok:
|
| |
- warnings.append("NOTE: new branch owner not owner of other branches,\n but primary devel owner is OK with EPEL branches.")
|
| |
- elif exists and not owned and items['New Branches'].find('EL') >= 0 and owners['devel']['primary'] in epel_ok_comaint:
|
| |
- warnings.append("NOTE: new branch owner not owner of other branches,\n but primary devel owner is OK with EPEL branches\n as long as they comaintain.")
|
| |
- elif exists and not owned:
|
| |
- warnings.append("WARNING: new branch owner not owner of other branches.")
|
| |
- warned = True
|
| |
-
|
| |
- if not firstfound:
|
| |
- warnings.append("WARNING: SCM request was not the last comment.")
|
| |
- warned = True
|
| |
- if not 'Package Name' in items:
|
| |
- warnings.append("WARNING: No package name supplied.")
|
| |
- warned = True
|
| |
- if not 'Owners' in items:
|
| |
- warnings.append("WARNING: No owners provided.")
|
| |
- warned = True
|
| |
- if not len(items['New Branches']):
|
| |
- warnings.append("WARNING: No new branches requested.")
|
| |
- for i in request['newbranches']:
|
| |
- if i not in branches:
|
| |
- warnings.append("WARNING: Invalid branch %s requested" % i)
|
| |
- warned = True
|
| |
-
|
| |
- req_string = change_request_string(items, bug)
|
| |
- bug_comment = 'Git done (by process-git-requests).\n'
|
| |
-
|
| |
- okprompt = 'Do it (yes=Yes, n=No, e=Edit request, s=Show ticket, b=Show ticket in browser, c=Comment, q=Quit)?'
|
| |
- if warned:
|
| |
- prompt = 'Warnings present!\nDo it (a=Accept warnings, n=No, e=Edit request, s=Show ticket, b=Show ticket in browser, c=Comment, q=Quit)?'
|
| |
- else:
|
| |
- prompt = okprompt
|
| |
-
|
| |
- # We have to loop until the user accepts the request
|
| |
- while 1:
|
| |
- # We have to loop until the user enters something that works
|
| |
- while 1:
|
| |
- clear()
|
| |
- if len(warnings):
|
| |
- print '\n'.join(warnings), "\n"
|
| |
- print req_string + "\nCurrent branch owners - comaintainers:\n" + owner_string
|
| |
- ok = raw_input(prompt)
|
| |
- if ok == 'a':
|
| |
- prompt = okprompt
|
| |
- warned = False
|
| |
- if ok == 'c':
|
| |
- bug_comment = edit_string('')
|
| |
- print bug_comment
|
| |
- ok = raw_input("\nPost this comment to the ticket (y/n)?")
|
| |
- if ok == 'y':
|
| |
- print "Updating bugzilla..."
|
| |
- bug.addcomment(bug_comment)
|
| |
- ok = raw_input("\nClear the fedora-cvs flag (y/n)?")
|
| |
- if ok == 'y':
|
| |
- print "Clearing the flag..."
|
| |
- bug.updateflags({'fedora-cvs':'X'})
|
| |
- return (False, True)
|
| |
- elif ok == 'e':
|
| |
- req_string = edit_string(req_string)
|
| |
- items=parse_prefixed_lines(req_string)
|
| |
- request = clean_request(items)
|
| |
- req_string = change_request_string(items, bug)
|
| |
- break
|
| |
- elif ok == 'n':
|
| |
- return (False, True)
|
| |
- elif ok == 'q':
|
| |
- return (False, False)
|
| |
- elif ok == 's':
|
| |
- print
|
| |
- display_bug(bug, allcomments)
|
| |
- elif ok == 'b':
|
| |
- webbrowser.open("https://bugzilla.redhat.com/" + str(bug.id), new=1)
|
| |
- elif ok == 'yes' and not warned:
|
| |
- bug_comment = edit_string(bug_comment)
|
| |
- print '\n', bug_comment
|
| |
- ok = raw_input('Go ahead (y/n)?')
|
| |
- if ok != 'y':
|
| |
- break
|
| |
- print 'Calling pkgdb...'
|
| |
- try:
|
| |
- edit_package(pkgdb, request)
|
| |
- except Exception, e:
|
| |
- print "Pkgdb call failed:"
|
| |
- print e
|
| |
- raw_input('\nPress enter to continue to the next ticket.')
|
| |
- return (False, True)
|
| |
-
|
| |
- print 'Updating bugzilla...'
|
| |
- # XXX Need to handle errors here - might be done, limburgher 2012-09-05
|
| |
- try:
|
| |
- bug.updateflags({'fedora-cvs':'+'})
|
| |
- except Exception, e:
|
| |
- print "Bugzilla call failed:"
|
| |
- print e
|
| |
- raw_input('\nPress enter to continue to the next ticket.')
|
| |
- return (False, True)
|
| |
- try:
|
| |
- bug.addcomment(bug_comment)
|
| |
- except Exception, e:
|
| |
- print "Bugzilla call failed:"
|
| |
- print e
|
| |
- raw_input('\nPress enter to continue to the next ticket.')
|
| |
- return (False, True)
|
| |
-
|
| |
- return (request['pkg'], True)
|
| |
- else:
|
| |
- pass
|
| |
-
|
| |
- if __name__ == '__main__':
|
| |
- processed = []
|
| |
- options = parse_commandline()
|
| |
-
|
| |
- if options.debug:
|
| |
- LOG.setLevel(logging.DEBUG)
|
| |
- PKGDBLOG.setLevel(logging.DEBUG)
|
| |
- elif options.verbose:
|
| |
- LOG.setLevel(logging.INFO)
|
| |
-
|
| |
- print "Connecting to bugzilla..."
|
| |
- try:
|
| |
- bz = bugzilla.Bugzilla(url=options.url)
|
| |
- except Exception, e:
|
| |
- print "Bugzilla call failed:"
|
| |
- print e
|
| |
- exit(1)
|
| |
-
|
| |
- print "Querying bugzilla..."
|
| |
- try:
|
| |
- (bugs, comments) = run_query(bz)
|
| |
- except Exception, e:
|
| |
- print "Bugzilla call failed:"
|
| |
- print e
|
| |
- exit(1)
|
| |
-
|
| |
- print "Done; got %d." % len(bugs)
|
| |
- if not len(bugs):
|
| |
- print "No requests to process!"
|
| |
- exit(0)
|
| |
-
|
| |
- bugcount = len(bugs)
|
| |
-
|
| |
- print "Making sure " + options.pkghost + " is available..."
|
| |
- try:
|
| |
- sshsock = socket.create_connection((options.pkghost, 80))
|
| |
- sshsock.close()
|
| |
- except Exception, e:
|
| |
- print options.pkghost + " unavailable."
|
| |
- print e
|
| |
- exit(1)
|
| |
-
|
| |
- print "Connecting to pkgdb..."
|
| |
- config = parse_pkgdb_config()
|
| |
- pkgdb = PkgDB(config['pkgdb.url'],
|
| |
- login_callback=pkgdb2client.ask_password)
|
| |
- pkgdb.username = options.user
|
| |
-
|
| |
-
|
| |
- print "Getting valid branches...."
|
| |
- collections = pkgdb.get_collections(
|
| |
- clt_status=['Active', 'Under Development'])
|
| |
- branches = dict(
|
| |
- (k,v) for (k,v) in map(
|
| |
- lambda q: (q['branchname'], 1),
|
| |
- collections['collections']))
|
| |
-
|
| |
- # Prune any obsolete branches
|
| |
- if OBSOLETE_BRANCH in branches:
|
| |
- del branches[OBSOLETE_BRANCH]
|
| |
- if 'EL-4' in branches:
|
| |
- del branches['EL-4']
|
| |
-
|
| |
- print "Connecting to FAS..."
|
| |
- fas = AccountSystem(username=options.user)
|
| |
- print "Done."
|
| |
- print
|
| |
-
|
| |
- # I think this reliably detects whether or not you've logged in
|
| |
- if bugs[0].assigned_to.find('@') < 0:
|
| |
- print "It looks as if you don't have a valid bugzilla cookie."
|
| |
- print "Please run 'bugzilla login' and try again."
|
| |
- exit(1)
|
| |
-
|
| |
- # Iterate over bugs
|
| |
- newre = re.compile('^New Package .* Request', re.MULTILINE)
|
| |
- changere = re.compile('^Package Change Request', re.MULTILINE)
|
| |
- bugcounter=1
|
| |
- for i in bugs:
|
| |
- firstfound = True
|
| |
- type = ''
|
| |
- print "Parsing bug %d - https://bugzilla.redhat.com/%d - processing %s of %s" % (i.id, i.id, str(bugcounter), str(bugcount))
|
| |
- for j in reversed(comments['bugs'][str(i.id)]['comments']):
|
| |
- if newre.search(j['text']):
|
| |
- type = 'new'
|
| |
- break
|
| |
- if changere.search(j['text']):
|
| |
- type = 'change'
|
| |
- break
|
| |
- firstfound = False
|
| |
- else:
|
| |
- if not process_no_request(i, comments['bugs'][str(i.id)]['comments']):
|
| |
- break
|
| |
-
|
| |
- if type == 'new':
|
| |
- (package, more) = process_new_request(i, j, comments['bugs'][str(i.id)]['comments'], firstfound, pkgdb, fas, branches)
|
| |
- if not more:
|
| |
- break
|
| |
- elif type == 'change':
|
| |
- (package, more) = process_change_request(i, j, comments['bugs'][str(i.id)]['comments'], firstfound, pkgdb, branches)
|
| |
- if not more:
|
| |
- break
|
| |
- bugcounter = bugcounter + 1
|
| |
-
|
| |
- if len(processed):
|
| |
- print '\nThe git repos/branches will be created in the background automagically.'
|
| |
- print 'If this does not work, please execute the following commands on pkgs.fedoraproject.org:'
|
| |
- print '/usr/local/bin/pkgdb_sync_git_branches.py ' + ' '.join(processed)
|
| |
-
|
| |
- sys.exit(0)
|
| |