#!/usr/bin/python -tt #-*- coding: utf-8 -*- # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ The idea of this program is to gather tickets from different project which are marked as 'easyfix' (or any other keyword for that matter). This version is a simple proof of concept, eventually it should be converted to an html page and this script run by a cron job of some sort. The different project to suscribe by email or a git repo or a page on the wiki. To be sorted out... """ 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 class MediaWiki(fedora.client.Wiki): """ Mediawiki class. Handles interaction with the Mediawiki. Code stollen from cnucnu: http://fedorapeople.org/gitweb?p=till/public_git/cnucnu.git;a=summary """ def __init__(self, base_url='https://fedoraproject.org/w/', *args, **kwargs): """ Instanciate a Mediawiki client. :arg base_url: base url of the mediawiki to query. """ super(MediaWiki, self).__init__(base_url, *args, **kwargs) def json_request(self, method="api.php", req_params=None, auth=False, **kwargs): """ Perform a json request to retrieve the content of a page. """ if req_params: req_params["format"] = "json" data = None for i in range(0, RETRIES+1): try: data = self.send_request(method, req_params, auth, **kwargs) except fedora.client.ServerError, ex: if i >= RETRIES: raise MediaWikiException( 'Could not contact the wiki -- error: %s' % ex) else: break if 'error' in data: raise MediaWikiException(data['error']['info']) return data def get_pagesource(self, titles): """ Retrieve the content of a given page from Mediawiki. :arg titles, the title of the page to return """ data = self.json_request(req_params={ 'action': 'query', 'titles': titles, 'prop': 'revisions', 'rvprop': 'content' } ) return data['query']['pages'].popitem()[1]['revisions'][0]['*'] class Project(object): """ Simple object representation of a project. """ def __init__(self): self.name = "" self.url = "" self.site = "" self.owner = "" self.tag = "" self.tickets = [] class Ticket(object): """ Simple object representation of a ticket. """ def __init__(self): self.id = "" self.url = "" self.title = "" self.status = "" self.type = "" self.component = "" def gather_bugzilla_easyfix(): """ From the Red Hat bugzilla, retrieve all new tickets flagged as easyfix. """ bugbz = bzclient.query( {'f1': 'keywords', 'o1': 'allwords', 'v1': 'easyfix', 'query_format': 'advanced', 'bug_status': ['NEW'], 'classification': 'Fedora'}) #print " {0} easyfix bugs retrieve from the BZ ".format(len(bugbz)) return bugbz def gather_project(): """ Retrieve all the projects which have subscribed to this idea. """ wiki = MediaWiki(base_url='https://fedoraproject.org/w/') page = wiki.get_pagesource("Easyfix") projects = [] for row in page.split('\n'): regex = re.search(' \* ([^ ]*) ([^ ]*)( [^ ]*)?', row) if regex: project = Project() project.name = regex.group(1) project.tag = regex.group(2) project.owner = regex.group(3) projects.append(project) return projects def get_open_tickets_for_keyword(project, keyword): """ For a given project return the tickets ID which have the given keyword attached. :arg project, name of the project on fedorahosted.org :arg keyword, search the trac for open tickets having this keyword in the keywords field. """ tickets = [] try: server = xmlrpclib.ServerProxy( 'https://fedorahosted.org/%s/rpc' % project) query = 'status=assigned&status=new&status=reopened&' \ 'keywords=~%s' % keyword for ticket in server.ticket.query(query): tickets.append(server.ticket.get(ticket)) except xmlrpclib.Error, err: print ' Could not retrieve information for project: %s' % project print ' Error: %s' % err return tickets def main(): """ For each projects which have suscribed in the correct place (fedoraproject wiki page), gather all the tickets containing the provided keyword. """ template = '/etc/fedora-gather-easyfix/template.html' if not os.path.exists(template): template = './template.html' if not os.path.exists(template): print 'No template found' return 1 try: projects = gather_project() except MediaWikiException, ex: print ex return ticket_num = 0 for project in projects: #print 'Project: %s' % project.name tickets = [] if project.name.startswith('github:'): project.name = project.name.split('github:')[1] project.url = 'http://github.com/%s/' % (project.name) project.site = 'github' url = 'https://api.github.com/repos/%s/issues' \ '?labels=%s&state=open' % (project.name, project.tag) stream = urllib2.urlopen(url) output = stream.read() jsonobj = json.loads(output) if jsonobj: for ticket in jsonobj: ticket_num = ticket_num + 1 ticketobj = Ticket() ticketobj.id = ticket['number'] ticketobj.title = ticket['title'] ticketobj.url = ticket['html_url'] ticketobj.status = ticket['state'] tickets.append(ticketobj) else: project.url = 'http://fedorahosted.org/%s/' % (project.name) project.site = 'trac' for ticket in get_open_tickets_for_keyword(project.name, project.tag): ticket_num = ticket_num + 1 ticketobj = Ticket() ticketobj.id = ticket[0] ticketobj.title = ticket[3]['summary'] ticketobj.url = 'http://fedorahosted.org/%s/ticket/%s' %( project, ticket[0]) ticketobj.status = ticket[3]['status'] ticketobj.type = ticket[3]['type'] ticketobj.component = ticket[3]['component'] tickets.append(ticketobj) project.tickets = tickets bzbugs = gather_bugzilla_easyfix() try: # Read in template stream = open(template, 'r') tplfile = stream.read() stream.close() # Fill the template mytemplate = Template(tplfile) html = mytemplate.render(projects=projects, bzbugs = bzbugs, ticket_num=ticket_num, bzbugs_num=len(bzbugs), date=datetime.datetime.now().strftime("%a %b %d %Y %H:%M")) # Write down the page stream = open('index.html', 'w') stream.write(to_bytes(html)) stream.close() except IOError, err: print 'ERROR: %s' % err if __name__ == '__main__': main()