From the wiki, I was unclear on whether the hook script replaced or augmented the one I already used to record ticket changes. Diffing them showed all lines changed, so I dug in. The script in
http://trac-hacks.org/svn/timingandestimationplugin/branches/trac0.11/scripts is in DOS mode, and the core trac script is not (as installed by pkgsrc on NetBSD, if that matters). So I converted it to \n endings and then edited it to reduce differences to the core hook script without changing behavior. Here's the output of 'diff -ub', so that line endings are ignored. I can send the full diff to anyone who wants it, or ideally be able to check it in. There are some further changes that seem appropriate, but I'm unsure so have left them noted in comments. I've also included the diff from the 0.11.3 commit hook to the my modified one. --- trac-post-commit.py.~3687~ 2009-03-16 15:13:54.000000000 -0400 +++ trac-post-commit.py 2009-03-16 15:30:06.000000000 -0400 @@ -1,5 +1,4 @@ #!/usr/bin/env python -#!/usr/bin/env python # trac-post-commit-hook # ---------------------------------------------------------------------------- @@ -24,28 +23,27 @@ # IN THE SOFTWARE. # ---------------------------------------------------------------------------- - - - -# Changes for the Timing and Estimation plugin +### Changes for the Timing and Estimation plugin +# +## Logging support for debugging this hook +# +## Support for specifying time spent in commit messages. # # "Blah refs #12 (1)" will add 1h to the spent time for issue #12 # "Blah refs #12 (spent 1.5)" will add 1h to the spent time for issue #12 # # As above it is possible to use complicated messages: # -# "Changed blah and foo to do this or that. Fixes #10 (1) and #12 (2), and refs #13 (0.5)." +# "Changed blah and foo to do this or that. Fixes #10 (1) and #12 (2), +# and refs #13 (0.5)." # -# This will close #10 and #12, and add a note to #13 and also add 1h spent time to #10, -# add 2h spent time to #12 and add 30m spent time to #13. +# This will close #10 and #12, and add a note to #13 and also add 1h +# spent time to #10, add 2h spent time to #12 and add 30m spent time +# to #13. # # Note that: # (spent 2), (sp 2) or simply (2) may be used for spent # ' ', ',', '&' or 'and' may be used references -# - - - # This Subversion post-commit hook script is meant to interface to the # Trac (http://www.edgewall.com/products/trac/) issue tracking/wiki/etc @@ -56,6 +54,7 @@ # # REPOS="$1" # REV="$2" +# TRAC_ENV="/path/to/tracenv" # # /usr/bin/python /usr/local/src/trac/contrib/trac-post-commit-hook \ # -p "$TRAC_ENV" -r "$REV" @@ -99,6 +98,32 @@ import os import sys from datetime import datetime +from optparse import OptionParser + +parser = OptionParser() +depr = '(not used anymore)' +parser.add_option('-e', '--require-envelope', dest='envelope', default='', + help=""" +Require commands to be enclosed in an envelope. +If -e[], then commands must be in the form of [closes #4]. +Must be two characters.""") +parser.add_option('-p', '--project', dest='project', + help='Path to the Trac project.') +parser.add_option('-r', '--revision', dest='rev', + help='Repository revision number.') +parser.add_option('-u', '--user', dest='user', + help='The user who is responsible for this action '+depr) +parser.add_option('-m', '--msg', dest='msg', + help='The log message to search '+depr) +parser.add_option('-c', '--encoding', dest='encoding', + help='The encoding used by the log message '+depr) +parser.add_option('-s', '--siteurl', dest='url', + help=depr+' the base_url from trac.ini will always be used.') + +(options, args) = parser.parse_args(sys.argv[1:]) + +if not 'PYTHON_EGG_CACHE' in os.environ: + os.environ['PYTHON_EGG_CACHE'] = os.path.join(options.project, '.egg-cache') from trac.env import open_environment from trac.ticket.notification import TicketNotifyEmail @@ -109,6 +134,7 @@ from trac.util.datefmt import utc from trac.versioncontrol.api import NoSuchChangeset +# Change logfile to point to someplace this script can write. logfile = "/var/trac/commithook.log" LOG = False @@ -125,30 +151,8 @@ def log (s, *params): pass -from optparse import OptionParser - -parser = OptionParser() -depr = '(not used anymore)' -parser.add_option('-e', '--require-envelope', dest='envelope', default='', - help=""" -Require commands to be enclosed in an envelope. -If -e[], then commands must be in the form of [closes #4]. -Must be two characters.""") -parser.add_option('-p', '--project', dest='project', - help='Path to the Trac project.') -parser.add_option('-r', '--revision', dest='rev', - help='Repository revision number.') -parser.add_option('-u', '--user', dest='user', - help='The user who is responsible for this action '+depr) -parser.add_option('-m', '--msg', dest='msg', - help='The log message to search '+depr) -parser.add_option('-c', '--encoding', dest='encoding', - help='The encoding used by the log message '+depr) -parser.add_option('-s', '--siteurl', dest='url', - help=depr+' the base_url from trac.ini will always be used.') - -(options, args) = parser.parse_args(sys.argv[1:]) - +# Hoisted out of class CommitHook. +# \todo Explain why. _supported_cmds = {'close': '_cmdClose', 'closed': '_cmdClose', 'closes': '_cmdClose', @@ -161,6 +165,7 @@ 'refs': '_cmdRefs', 'see': '_cmdRefs'} +# Regexps are extended to include "(1)" and "(spent 1)". ticket_prefix = '(?:#|(?:ticket|issue|bug)[: ]?)' time_pattern = r'[ ]?(?:\((?:(?:spent|sp)[ ]?)?(-?[0-9]*(?:\.[0-9]+)?)\))?' ticket_reference = ticket_prefix + '[0-9]+'+time_pattern @@ -171,26 +176,25 @@ command_re = re.compile(ticket_command, re.IGNORECASE) ticket_re = re.compile(ticket_prefix + '([0-9]+)', re.IGNORECASE) - if options.envelope: ticket_command = r'\%s%s\%s' % (options.envelope[0], ticket_command, options.envelope[1]) +# \todo Why is this being done twice? command_re = re.compile(ticket_command, re.IGNORECASE) ticket_re = re.compile(ticket_prefix + '([0-9]+)'+time_pattern, re.IGNORECASE) class CommitHook: - + # \todo Explain why this is here. def init_env(self, project): self.env = open_environment(project) - def __init__(self, project=options.project, author=options.user, rev=options.rev, url=options.url): self.init_env( project ) - repos = self.env.get_repository() repos.sync() + # Instead of bothering with the encoding, we'll use unicode data # as provided by the Trac versioncontrol API (#1310). try: @@ -203,6 +207,7 @@ self.now = datetime.now(utc) cmd_groups = command_re.findall(self.msg) + log ("cmd_groups:%s", cmd_groups) tickets = {} for cmd, tkts, xxx1, xxx2 in cmd_groups: @@ -211,10 +216,10 @@ if funcname: for tkt_id, spent in ticket_re.findall(tkts): func = getattr(self, funcname) + # \todo catch up on upstream spiffiness lst = tickets.setdefault(tkt_id, []) lst.append([func, spent]) - for tkt_id, vals in tickets.iteritems(): log ("tkt_id:%s, vals%s ", tkt_id, vals) spent_total = 0.0 @@ -233,6 +238,7 @@ for change in tm.grouped_changelog_entries(ticket, db): if change['permanent']: cnum += 1 + if spent_total: self._setTimeTrackerFields(ticket, spent_total) ticket.save_changes(self.author, self.msg, self.now, db, cnum+1) @@ -263,7 +269,6 @@ if (ticket.values.has_key('hours')): ticket['hours'] = str(spentTime) - if __name__ == "__main__": if len(sys.argv) < 5: print "For usage: %s --help" % (sys.argv[0]) @@ -271,4 +276,3 @@ print "Note that the deprecated options will be removed in Trac 0.12." else: CommitHook() - --- /usr/pkg/share/examples/trac/trac-post-commit-hook 2009-03-03 12:26:03.000000000 -0500 +++ trac-post-commit.py 2009-03-16 15:30:06.000000000 -0400 @@ -1,4 +1,4 @@ -#!/usr/pkg/bin/python2.5 +#!/usr/bin/env python # trac-post-commit-hook # ---------------------------------------------------------------------------- @@ -23,6 +23,28 @@ # IN THE SOFTWARE. # ---------------------------------------------------------------------------- +### Changes for the Timing and Estimation plugin +# +## Logging support for debugging this hook +# +## Support for specifying time spent in commit messages. +# +# "Blah refs #12 (1)" will add 1h to the spent time for issue #12 +# "Blah refs #12 (spent 1.5)" will add 1h to the spent time for issue #12 +# +# As above it is possible to use complicated messages: +# +# "Changed blah and foo to do this or that. Fixes #10 (1) and #12 (2), +# and refs #13 (0.5)." +# +# This will close #10 and #12, and add a note to #13 and also add 1h +# spent time to #10, add 2h spent time to #12 and add 30m spent time +# to #13. +# +# Note that: +# (spent 2), (sp 2) or simply (2) may be used for spent +# ' ', ',', '&' or 'and' may be used references + # This Subversion post-commit hook script is meant to interface to the # Trac (http://www.edgewall.com/products/trac/) issue tracking/wiki/etc # system. @@ -112,35 +134,64 @@ from trac.util.datefmt import utc from trac.versioncontrol.api import NoSuchChangeset +# Change logfile to point to someplace this script can write. +logfile = "/var/trac/commithook.log" +LOG = False + +if LOG: + f = open (logfile,"w") + f.write("Begin Log\n") + f.close() + def log (s, *params): + f = open (logfile,"a") + f.write(s % params) + f.write("\n") + f.close() +else: + def log (s, *params): + pass + +# Hoisted out of class CommitHook. +# \todo Explain why. +_supported_cmds = {'close': '_cmdClose', + 'closed': '_cmdClose', + 'closes': '_cmdClose', + 'fix': '_cmdClose', + 'fixed': '_cmdClose', + 'fixes': '_cmdClose', + 'addresses': '_cmdRefs', + 're': '_cmdRefs', + 'references': '_cmdRefs', + 'refs': '_cmdRefs', + 'see': '_cmdRefs'} + +# Regexps are extended to include "(1)" and "(spent 1)". ticket_prefix = '(?:#|(?:ticket|issue|bug)[: ]?)' -ticket_reference = ticket_prefix + '[0-9]+' -ticket_command = (r'(?P<action>[A-Za-z]*).?' +time_pattern = r'[ ]?(?:\((?:(?:spent|sp)[ ]?)?(-?[0-9]*(?:\.[0-9]+)?)\))?' +ticket_reference = ticket_prefix + '[0-9]+'+time_pattern +support_cmds_pattern = '|'.join(_supported_cmds.keys()) +ticket_command = (r'(?P<action>(?:%s))[ ]*' '(?P<ticket>%s(?:(?:[, &]*|[ ]?and[ ]?)%s)*)' % - (ticket_reference, ticket_reference)) + (support_cmds_pattern,ticket_reference, ticket_reference)) +command_re = re.compile(ticket_command, re.IGNORECASE) +ticket_re = re.compile(ticket_prefix + '([0-9]+)', re.IGNORECASE) if options.envelope: ticket_command = r'\%s%s\%s' % (options.envelope[0], ticket_command, options.envelope[1]) -command_re = re.compile(ticket_command) -ticket_re = re.compile(ticket_prefix + '([0-9]+)') +# \todo Why is this being done twice? +command_re = re.compile(ticket_command, re.IGNORECASE) +ticket_re = re.compile(ticket_prefix + '([0-9]+)'+time_pattern, re.IGNORECASE) class CommitHook: - _supported_cmds = {'close': '_cmdClose', - 'closed': '_cmdClose', - 'closes': '_cmdClose', - 'fix': '_cmdClose', - 'fixed': '_cmdClose', - 'fixes': '_cmdClose', - 'addresses': '_cmdRefs', - 're': '_cmdRefs', - 'references': '_cmdRefs', - 'refs': '_cmdRefs', - 'see': '_cmdRefs'} + # \todo Explain why this is here. + def init_env(self, project): + self.env = open_environment(project) def __init__(self, project=options.project, author=options.user, rev=options.rev, url=options.url): - self.env = open_environment(project) + self.init_env( project ) repos = self.env.get_repository() repos.sync() @@ -157,21 +208,29 @@ cmd_groups = command_re.findall(self.msg) + log ("cmd_groups:%s", cmd_groups) tickets = {} - for cmd, tkts in cmd_groups: - funcname = CommitHook._supported_cmds.get(cmd.lower(), '') + for cmd, tkts, xxx1, xxx2 in cmd_groups: + log ("cmd:%s, tkts%s ", cmd, tkts) + funcname = _supported_cmds.get(cmd.lower(), '') if funcname: - for tkt_id in ticket_re.findall(tkts): + for tkt_id, spent in ticket_re.findall(tkts): func = getattr(self, funcname) - tickets.setdefault(tkt_id, []).append(func) - - for tkt_id, cmds in tickets.iteritems(): + # \todo catch up on upstream spiffiness + lst = tickets.setdefault(tkt_id, []) + lst.append([func, spent]) + + for tkt_id, vals in tickets.iteritems(): + log ("tkt_id:%s, vals%s ", tkt_id, vals) + spent_total = 0.0 try: db = self.env.get_db_cnx() ticket = Ticket(self.env, int(tkt_id), db) - for cmd in cmds: + for (cmd, spent) in vals: cmd(ticket) + if spent: + spent_total += float(spent) # determine sequence number... cnum = 0 @@ -180,6 +239,8 @@ if change['permanent']: cnum += 1 + if spent_total: + self._setTimeTrackerFields(ticket, spent_total) ticket.save_changes(self.author, self.msg, self.now, db, cnum+1) db.commit() @@ -188,6 +249,8 @@ except Exception, e: # import traceback # traceback.print_exc(file=sys.stderr) + log('Unexpected error while processing ticket ' \ + 'ID %s: %s' % (tkt_id, e)) print>>sys.stderr, 'Unexpected error while processing ticket ' \ 'ID %s: %s' % (tkt_id, e) @@ -199,6 +262,12 @@ def _cmdRefs(self, ticket): pass + def _setTimeTrackerFields(self, ticket, spent): + log ("Setting ticket:%s spent: %s", ticket, spent) + if (spent != ''): + spentTime = float(spent) + if (ticket.values.has_key('hours')): + ticket['hours'] = str(spentTime) if __name__ == "__main__": if len(sys.argv) < 5:
pgpTKxk9D7fUj.pgp
Description: PGP signature
