From f1b8a0aae2ee64069a208b388b1478c6948775af Mon Sep 17 00:00:00 2001 From: "jkeating@localhost.localdomain" Date: Tue, 4 Aug 2009 15:57:16 -0700 Subject: Add fedora-hosted fedora-hosted is a command line tool to ineract with Fedora Hosted's Trac server via xmlrpc. It requires the offtrac python library as indicated in the spec file. --- ChangeLog | 2 + Makefile.am | 9 +- NEWS | 3 + configure.ac | 2 +- fedora-packager.spec | 7 +- src/fedora-hosted | 242 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 261 insertions(+), 4 deletions(-) create mode 100755 src/fedora-hosted diff --git a/ChangeLog b/ChangeLog index 1ad9626..7dc8386 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ +* Jesse Keating - 0.3.8 +- add fedora-hosted * Dennis Gilmore - 0.3.7 - make sure user_cert is defined before refrencing it in fedora-cvs.py * Dennis Gilmore - 0.3.6 diff --git a/Makefile.am b/Makefile.am index f694402..2f4ffdf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ -bin_SCRIPTS = fedora-cvs fedora-packager-setup fedoradev-pkgowners fedora-cert fedora-getsvn rpmbuild-md5 +bin_SCRIPTS = fedora-cvs fedora-packager-setup fedoradev-pkgowners fedora-cert fedora-getsvn fedora-hosted rpmbuild-md5 CLEANFILES = $(bin_SCRIPTS) -EXTRA_DIST = src/fedora-cvs.py src/fedora-packager-setup.py src/fedoradev-pkgowners src/fedora-cert.py src/fedora-getsvn src/rpmbuild-md5 +EXTRA_DIST = src/fedora-cvs.py src/fedora-packager-setup.py src/fedoradev-pkgowners src/fedora-cert.py src/fedora-getsvn fedora-hosted src/rpmbuild-md5 fedora-cvs: $(srcdir)/src/fedora-cvs.py rm -f fedora-cvs @@ -27,6 +27,11 @@ fedora-getsvn: $(srcdir)/src/fedora-getsvn cp -p $(srcdir)/src/fedora-getsvn fedora-getsvn chmod ugo+x fedora-getsvn +fedora-hosted: $(srcdir)/src/fedora-hosted + rm -f fedora-hosted + cp -p $(srcdir)/src/fedora-getsvn fedora-hosted + chmod ugo+x fedora-hosted + rpmbuild-md5: $(srcdir)/src/rpmbuild-md5 rm -f rpmbuild-md5 cp -p $(srcdir)/src/rpmbuild-md5 rpmbuild-md5 diff --git a/NEWS b/NEWS index 6dd9604..916363d 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,6 @@ +Aug 04 2009 +add fedora-hosted, a cli interface to our Trac setup + Jul 13 2009 add rpmbuild-md5 it creates rpms with old style hashes diff --git a/configure.ac b/configure.ac index c4fcc49..918c051 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([fedora-packager], [0.3.7]) +AC_INIT([fedora-packager], [0.3.8]) AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip]) AC_PATH_PROGS(PYTHON, python) AC_PATH_PROGS(BASH, sh bash) diff --git a/fedora-packager.spec b/fedora-packager.spec index 4f14fae..f1007c4 100644 --- a/fedora-packager.spec +++ b/fedora-packager.spec @@ -1,5 +1,5 @@ Name: fedora-packager -Version: 0.3.7 +Version: 0.3.8 Release: 1%{?dist} Summary: Tools for setting up a fedora maintainer environment @@ -14,6 +14,7 @@ Requires: rpm-build rpmdevtools rpmlint Requires: mock cvs curl wget Requires: pyOpenSSL python-pycurl Requires: redhat-rpm-config +Requires: offtrac BuildArch: noarch @@ -45,10 +46,14 @@ rm -rf $RPM_BUILD_ROOT %{_bindir}/fedoradev-pkgowners %{_bindir}/fedora-cert %{_bindir}/fedora-getsvn +%{_bindir}/fedora-hosted %{_bindir}/rpmbuild-md5 %changelog +* Tue Aug 04 2009 Jesse Keating - 0.3.8-1 +- Add fedora-hosted and require offtrac + * Thu Jul 30 2009 Dennis Gilmore - 0.3.7-1 - define user_cert in fedora-cvs before refrencing it diff --git a/src/fedora-hosted b/src/fedora-hosted new file mode 100755 index 0000000..c58a20a --- /dev/null +++ b/src/fedora-hosted @@ -0,0 +1,242 @@ +#!/usr/bin/python +# fedora-hosted - a commandline frontend for the Fedora Hosted Projects Trac +# +# Copyright (C) 2008 Red Hat Inc. +# Author: Jesse Keating +# +# 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. See http://www.gnu.org/copyleft/gpl.html for +# the full text of the license. + +# TODO: this file should probably go away and be far more generic +# And we should load specific things like url structure from a config +# store of some sort. + +import getpass +import optparse +import offtrac +import sys +import time + +# Define some constants +BASEURL = 'fedorahosted.org/' + +# List currently available commands +cmdlist = ('list-tickets', 'list-milestones', 'ticket-info', 'milestone-info', + 'new-ticket', 'new-milestone', 'update-ticket') + +# Define some functions +def setup_action_parser(action): + """Setup parsers for the various action types""" + + usage = "usage: %%prog %s [options]" % action + p = optparse.OptionParser(usage = usage) + + if action == "list-tickets": + p.add_option("--owner", "-o") + p.add_option("--status", "-s", default="!=closed", + help="Query string for status, default is '!=closed'") + p.add_option("--component", "-c") + p.add_option("--type", "-t") + +# elif action == "list-milestones": +# p.add_option("--name", "-n", +# help="Show information about a particular milestone") +# p.add_option("--all", "-a", action="store_true", +# help="Show all milestones, otherwise only show active.") + + elif action == "ticket-info": + p.set_usage("usage: %%prog %s [ticket numbers]" % action) + + elif action == "milestone_info": + p.set_usage("usage: %%prog %s [milestones]" % action) + + elif action == "new-ticket": + p.add_option("--summary", "-s", help="REQUIRED!") + p.add_option("--description", "-d", help="REQUIRED!") + p.add_option("--type", "-t", default=None) + p.add_option("--priority", "-p", default=None) + p.add_option("--milestone", "-m", default=None) + p.add_option("--component", "-C", default=None) + p.add_option("--version", "-v", default=None) + p.add_option("--keyword", "-k", action="append", + help="Keyword to add, can be used multiple times.") + p.add_option("--assignee", "-a", default=None) + p.add_option("--cc", action="append", + help="Carbon Copy address, can be used multiple times.") + # This one is a little backwards. The rpc call is actually notify, + # and defaults to false, but we want to default to true. + p.add_option("--stealth", action="store_false", default=True, + help="Suppress initial notification of this ticket.") + + elif action == "update-ticket": + p.add_option("--ticket", "-n", help="Ticket number. REQUIRED!") + p.add_option("--comment", "-c", default='') + p.add_option("--summary", "-s", default=None) + p.add_option("--description", "-d", default=None) + p.add_option("--type", "-t", default=None) + p.add_option("--priority", "-p", default=None) + p.add_option("--milestone", "-m", default=None) + p.add_option("--component", "-C", default=None) + p.add_option("--version", "-v", default=None) + p.add_option("--keyword", "-k", action="append", + help="Keyword to add, can be used multiple times.") + p.add_option("--assignee", "-a", default=None) + p.add_option("--cc", action="append", + help="Carbon Copy address, can be used multiple times.") + p.add_option("--status", "-S", default=None) + p.add_option("--resolution", "-r", default=None) + # This one is a little backwards. The rpc call is actually notify, + # and defaults to false, but we want to default to true. + p.add_option("--stealth", action="store_false", default=True, + help="Suppress notification of this update.") + + elif action == "new-milestone": + p.add_option("--name", "-n", help="REQUIRED!") + p.add_option("--description", "-d", default=None) + p.add_option("--due", "-D", default=None, + help="Due date in MM-DD-YY format.") + + return p + + +# get command line options +usage = "usage: %prog [global options] COMMAND [options]" +usage += "\nCommands: %s" % ', '.join(cmdlist) +parser = optparse.OptionParser(usage=usage) +parser.disable_interspersed_args() + +# TODO: Try to get this info from fedora config files +parser.add_option("--user", "-u") +parser.add_option("--password", "-p") +parser.add_option("--project", "-P") + +# Parse our global options +(opts, args) = parser.parse_args() + +# See if we got a command +if len(args) and args[0] in cmdlist: + action = args.pop(0) +else: + parser.print_help() + sys.exit(1) + +# Parse the command +action_parser = setup_action_parser(action) +(actopt, actargs) = action_parser.parse_args(args) + +if not opts.user: + opts.user=raw_input('Username: ') + +if not opts.password: + opts.password=getpass.getpass('Password for %s: ' % opts.user) + +if not opts.project: + opts.project=raw_input('Project space: ') + + +# Create the TracServ object +uri = 'https://%s:%s@%s/%s/login/xmlrpc' % (opts.user, + opts.password, + BASEURL, + opts.project) +trac = offtrac.TracServer(uri) + +# Try to do something +if action == "list-tickets": + # setup the query string + query = "status%s" % actopt.status + if actopt.owner: + query += "&owner=%s" % actopt.owner + if actopt.component: + query += "&component=%s" % actopt.component + if actopt.type: + query += "&type=%s" % actopt.type + + results = trac.query_tickets(query) + print results + +elif action == "list-milestones": + results = trac.list_milestones() + print results + +elif action == "ticket-info": + if not actargs: # FIXME, this isn't working + action_parser.print_help() + sys.exit(1) + # Setup the trac object for multicall + trac.setup_multicall() + for number in actargs: + trac.get_ticket(number) + # Do the multicall and print out the results + for result in trac.do_multicall(): + print result + +elif action == "milestone-info": + if not actargs: # FIXME, this isn't working + action_parser.print_help() + sys.exit(1) + trac.setup_multicall() + for milestone in actargs: + trac.get_milestone(milestone) + for result in trac.do_multicall(): + print result + +elif action == "new-ticket": + # Check to make sure we got all we need + if actopt.summary and actopt.description: + pass + else: + action_parser.print_help() + sys.exit(1) + # Wrap up our keywords and cc into one string, if any + keywords = None + ccs = None + if actopt.keyword: + keywords = ' '.join(actopt.keyword) + if actopt.cc: + ccs = ' '.join(actopt.cc) + + result = trac.create_ticket(actopt.summary, actopt.description, + actopt.type, actopt.priority, actopt.milestone, + actopt.component, actopt.version, keywords, + actopt.assignee, ccs, actopt.stealth) + print result + +elif action == "update-ticket": + # Check to make sure we got all we need + if actopt.ticket: + pass + else: + action_parser.print_help() + sys.exit(1) + # Wrap up our keywords and cc into one string, if any + keywords = None + ccs = None + if actopt.keyword: + keywords = ' '.join(actopt.keyword) + if actopt.cc: + ccs = ' '.join(actopt.cc) + + result = trac.update_ticket(actopt.ticket, actopt.comment, actopt.summary, + actopt.type, actopt.description, + actopt.priority, actopt.milestone, + actopt.component, actopt.version, keywords, + ccs, actopt.status, actopt.resolution, + actopt.assignee, actopt.stealth) + print result + +elif action == "new-milestone": + if not actopt.name: + action_parser.print_help() + sys.exit(1) + # Convert due date to seconds if needed + due = None + if actopt.due: + due = int(time.mktime(time.strptime(actopt.due, "%m-%d-%y"))) + + result = trac.create_milestone(actopt.name, actopt.description, due) + print result # The result here is "0" if successful, printing isn't fun + -- cgit