Beispiel #1
0
def command(args):
    import sys

    from sr.tools.trac import Ticket, TracProxy, WrongServer

    try:
        server = TracProxy()
    except WrongServer:
        print("Error: The specified server is not a Trac instance",
              file=sys.stderr)
        sys.exit(1)

    t = Ticket(args.ticket, server)

    for n in args.deps:
        t.deps.remove(n)

    if args.m is not None:
        msg = args.m
        msg += "\n\n"
    else:
        msg = ""

    msg += "Removing dependencies:"
    for n in args.deps:
        msg += "\n * #{0}".format(n)

    updated = t.cleanup(dry_run=args.dry_run, msg=msg)

    if updated:
        if args.dry_run:
            print("Ticket would have been updated if not for --dry-run.")
        else:
            print("Ticket updated.")
Beispiel #2
0
def command(args):
    import sys

    from sr.tools.trac import Ticket, TracProxy, WrongServer

    try:
        server = TracProxy()
    except WrongServer:
        print("Error: The specified server is not a Trac instance",
              file=sys.stderr)
        sys.exit(1)

    tickets = {}

    done = set()
    todo = set([args.ticket])

    print("digraph G {")
    print("rankdir=LR;")

    while len(todo):
        for num in list(todo):
            t = Ticket(num, server)
            tickets[num] = t

            for dep in t.deps:
                if dep not in done:
                    todo.add(dep)

                print("{0} -> {1};".format(dep, num))

            done.add(num)
            todo.remove(num)

    for num, ticket in tickets.items():
        if args.summaries:
            label = "#{}: {}".format(num, ticket.summary)
        else:
            label = "#{}".format(num)
        props = {"label": label, "URL": ticket.url}

        if ticket.status == "closed":
            props["style"] = "filled"
            props["color"] = "grey"

        propstr = ""
        for name, val in props.items():
            propstr += """{0}="{1}" """.format(name, val)

        print("{0} [{1}]".format(num, propstr))

    print("}")
Beispiel #3
0
def command(args):
    import re
    import sys
    import six.moves.xmlrpc_client as xmlrpclib

    from sr.tools import spending
    from sr.tools.trac import TracProxy

    try:
        root = spending.find_root()
    except spending.NotSpendingRepo:
        print(
            "Please run in spending.git top level directory", file=sys.stderr)
        exit(1)

    spends = spending.load_transactions(root)

    spendsumgrp = {}
    for s in spends:
        if s.trac in spendsumgrp:
            spendsumgrp[s.trac] += float(s.cost)
        else:
            spendsumgrp[s.trac] = float(s.cost)

    server = TracProxy(anon=True)
    mserver = xmlrpclib.MultiCall(server)

    tickets = server.ticket.query("status!=closed&component=Purchasing")
    for ticket in tickets:
        mserver.ticket.get(ticket)

    costsumgrp = {}
    for ticket in mserver():
        match = re.search(
            'Total cost: \xa3([0-9.]+)', ticket[3]['description'])
        if match is None:
            print("Unable to determine cost for ticket " +
                  str(ticket[0]) + ". Invalid formatting")
            continue

        if ticket[0] in costsumgrp:
            costsumgrp[ticket[0]] += float(match.groups()[0])
        else:
            costsumgrp[ticket[0]] = float(match.groups()[0])

    for val in costsumgrp:
        if spendsumgrp[val] != costsumgrp[val]:
            print("Ticket " + str(val) + " does not match transactions")
            print("\tTicket cost:  £" + str(costsumgrp[val]))
            print("\tTransactions: £" + str(spendsumgrp[val]))
Beispiel #4
0
def command(args):
    import sys

    from sr.tools.trac import Ticket, TracProxy, WrongServer

    try:
        server = TracProxy()
    except WrongServer:
        print("Error: The specified server is not a Trac instance",
              file=sys.stderr)
        sys.exit(1)

    t = Ticket(args.ticket, server)

    current = set(t.deps)
    new = set(args.deps)

    to_add = new - current
    already = new - to_add

    if len(already):
        for n in already:
            print('#{0} is already a dep of #{1}'.format(n, args.ticket),
                  file=sys.stderr)

    if len(to_add) == 0:
        sys.exit("No new dependencies to add to #{0}".format(args.ticket))

    t.deps += to_add

    if args.m is not None:
        msg = args.m
        msg += "\n\n"
    else:
        msg = ""

    msg += "Adding dependencies:"
    for n in to_add:
        msg += "\n * #{0}".format(n)

    updated = t.cleanup(dry_run=args.dry_run, msg=msg)

    if updated:
        if args.dry_run:
            print("Ticket would have been updated if not for --dry-run.")
        else:
            print("Ticket updated.")
Beispiel #5
0
def command(args):
    import os
    import sys
    from six.moves.xmlrpc_client import Binary

    from sr.tools.trac import TracProxy, WrongServer

    try:
        server = TracProxy(server=args.server, port=args.port)
    except WrongServer:
        print("Error: The specified server is not a Trac instance",
              file=sys.stderr)
        sys.exit(1)

    with open(args.filename, "r") as f:
        content = f.read()

    server.ticket.putAttachment(args.ticket, os.path.basename(args.filename),
                                args.desc, Binary(content))
Beispiel #6
0
def command(args):
    import sys

    from sr.tools.trac import Ticket, TracProxy, WrongServer

    try:
        server = TracProxy()
    except WrongServer:
        print("Error: The specified server is not a Trac instance",
              file=sys.stderr)
        sys.exit(1)

    search_ticket = args.ticket

    query = "description=~{}".format(search_ticket)
    matches = server.ticket.query(query)

    deps = []
    refs = []
    for num in matches:
        t = Ticket(num, server)
        if search_ticket in t.deps:
            deps.append(t)
        else:
            refs.append(t)

    if len(deps):
        print("The following tickets depend on {}:".format(search_ticket))
        for t in deps:
            print("\t{} [{}]".format(t, t.url))
    else:
        print("Nothing depends on {}".format(search_ticket))

    if len(refs):
        print("The following tickets appear to reference {}:".format(
            search_ticket))
        for t in refs:
            print("\t{} [{}]".format(t, t.url))
Beispiel #7
0
def command(args):
    import sys

    from sr.tools import spending
    from sr.tools.trac import TracProxy

    transactions = spending.load_transactions("./")
    p = TracProxy(anon=True)
    tickets = p.ticket.query(
        "component=purchasing&max=0&resolution=fixed&status=closed")

    counts = {}
    for t in tickets:
        if t < 821 and t not in []:
            # Tickets before #839 except for those listed above weren't
            # budgeted
            continue

        counts[t] = 0

    # Tickets that have been prematurely added to spending.git
    premature = []

    for t in transactions:
        if t.trac not in counts:
            premature.append(t.trac)
            continue

        counts[t.trac] += 1

    missing = []
    for tnum, count in counts.items():
        if count == 0:
            missing.append(tnum)

    missing.sort()

    if len(missing):
        print("{0} trac tickets with no spending.git "
              "entry:".format(len(missing)))
        for t in missing:
            print("{0:10} -- http://srobo.org/trac/ticket/{0}".format(t))
    else:
        print("All resolved purchasing tickets exist in spending.git :-)")

    if len(premature):
        print("-" * 40)
        print("Grabbing ticket information...", end='')
        sys.stdout.flush()

        states = {}
        for t in premature:
            info = p.ticket.get(t)[3]
            s = (info["status"], info["resolution"])

            if s not in states:
                states[s] = []

            states[s].append(t)

        print("done")

        print("{0} purchasing tickets have been added to spending.git "
              "before being closed.".format(len(premature)))
        print()
        print("This is non-fatal, "
              "and generally means that there is more treasurer-related")
        print("action to be taken on them "
              "(maybe the treasurer is waiting for some information).")
        print()

        for state, tickets in states.items():
            tickets.sort()

            print("{0} tickets in state {1}:{2}:".format(
                len(tickets), state[0], state[1]))
            for t in tickets:
                print("{0:10} -- http://srobo.org/trac/ticket/{0}".format(t))
            print()

    open_tickets = set(p.ticket.query("component=purchasing&max=0&status=new"))

    print("There are {0} unresolved purchasing tickets in trac right now.".
          format(len(open_tickets)))
    print("Here are the ones that don't exist in spending.git")
    print("(note that they don't need to yet)")

    n = list(open_tickets.difference(premature))
    n.sort()

    for t in n:
        print("{0:10} -- http://srobo.org/trac/ticket/{0}".format(t))
Beispiel #8
0
def command(args):
    import datetime

    import sr.tools.spending as srspending
    import sr.tools.budget as srbudget
    from sr.tools.trac import TracProxy, WrongServer

    try:
        spending_root = srspending.find_root()
    except srspending.NotSpendingRepo:
        print("Please run in spending.git top level directory",
              file=sys.stderr)
        sys.exit(1)

    try:
        budget = srspending.load_budget_with_spending(spending_root)
    except srbudget.NoBudgetConfig as nbc:
        print("Error:", nbc.message, file=sys.stderr)
        print("Have you initialised the budget submodule?", file=sys.stderr)
        print("If not, run 'git submodule update --init'.", file=sys.stderr)
        sys.exit(1)

    if args.spend_file is not None:
        spend_request = SpendRequest(args.spend_file)
    else:
        spend_request = SpendRequest.from_editor()

    ticket_text = "Payee: {} \\\\\n".format(spend_request.username)

    if spend_request.supplier_url is None:
        ticket_text += "Supplier: {} \\\\\n".format(spend_request.supplier)
    else:
        ticket_text += "Supplier: [{url} {supplier}] \\\\\n" \
                       .format(url=spend_request.supplier_url,
                               supplier=spend_request.supplier)

    budget_line_totals = {}

    for purchase in spend_request.purchases:
        try:
            budget_line = budget.path(purchase.budget_line)
        except KeyError:
            # TODO: Move this check up into the parser so it's caught and the
            # user can fix it
            print('Budget line "{0}" not found', file=sys.stderr)
            sys.exit(1)

        bl_request_total = D(0)

        ticket_text += """
    === Items from [budget:{budget_line}] ===
    {summary} \\\\
    ||= '''Item''' =||= '''Cost''' =||
    """.format(budget_line=purchase.budget_line, summary=purchase.summary)

        for item in purchase.items:
            ticket_text += "|| {desc} || £{cost} ||\n".format(desc=item.desc,
                                                              cost=item.cost)

            bl_request_total += item.cost

        # How much has already been spent against this budget line
        spent = budget_line.spent

        req_total = spent + bl_request_total

        # It is over the limit?
        if req_total > budget_line.cost:
            print(
                "Warning: This purchase exceeds the budget line '{0}'".format(
                    purchase.budget_line))
            print("\tBudget line's value: £{0}".format(budget_line.cost))
            print("\tRequested Expenditure: £{0} ({1}%)".format(
                req_total, 100 * (req_total) / budget_line.cost))
            if not input("Continue anyway? [y/N] ").lower() == 'y':
                sys.exit()

        if purchase.budget_line not in budget_line_totals:
            budget_line_totals[purchase.budget_line] = D(0)
        budget_line_totals[purchase.budget_line] += bl_request_total

    ticket_text += """
    === Budget Line Totals ===
    ||= '''Budget Line''' =||= '''Total''' =||
    """
    for line, total in budget_line_totals.items():
        ticket_text += "|| [budget:{line}] || £{total} ||\n" \
                       .format(line=line, total=total)

    print(ticket_text)

    if args.dry_run:
        print("Stopping before actually creating ticket.")
        sys.exit(0)

    try:
        server = TracProxy(server=args.server, port=args.port)
    except WrongServer:
        print("Error: The specified server is not a Trac instance",
              file=sys.stderr)
        sys.exit(1)

    ticketNum = server.ticket.create(spend_request.summary, ticket_text, {
        'component': "Purchasing",
        'owner': "treasurer",
        'type': "task"
    })

    if not ticketNum > 0:
        print("Unable to create a valid ticket")
        sys.exit()

    if args.port == 443:
        hostname = args.server
    else:
        hostname = "{0}:{1}".format(args.server, args.port)

    print("Purchasing ticket created: https://{0}/trac/ticket/{1}".format(
        hostname, ticketNum))

    print("Spending Entries:")

    for purchase in spend_request.purchases:
        print()
        today = datetime.date.today()

        i = "{date} ! {summary}\n"
        i += "    {account}\t£{amount}\n"
        i += "    Liabilities:{payee}\n"
        i += "    ; trac: #{trac}"

        print(
            i.format(date=today.isoformat(),
                     summary=purchase.summary,
                     account=srspending.budget_line_to_account(
                         purchase.budget_line),
                     amount=sum([x.cost for x in purchase.items]),
                     payee=spend_request.username,
                     trac=ticketNum))