comparison examples/trac/contrib/trac-post-commit-hook @ 39:71ecbe90aafc

Copy Trac to main branch.
author cmlenz
date Mon, 03 Jul 2006 18:53:27 +0000
parents
children
comparison
equal deleted inserted replaced
38:fec9f4897415 39:71ecbe90aafc
1 #!/usr/bin/env python
2
3 # trac-post-commit-hook
4 # ----------------------------------------------------------------------------
5 # Copyright (c) 2004 Stephen Hansen
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to
9 # deal in the Software without restriction, including without limitation the
10 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11 # sell copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23 # IN THE SOFTWARE.
24 # ----------------------------------------------------------------------------
25
26 # This Subversion post-commit hook script is meant to interface to the
27 # Trac (http://www.edgewall.com/products/trac/) issue tracking/wiki/etc
28 # system.
29 #
30 # It should be called from the 'post-commit' script in Subversion, such as
31 # via:
32 #
33 # REPOS="$1"
34 # REV="$2"
35 # LOG=`/usr/bin/svnlook log -r $REV $REPOS`
36 # AUTHOR=`/usr/bin/svnlook author -r $REV $REPOS`
37 # TRAC_ENV='/somewhere/trac/project/'
38 # TRAC_URL='http://trac.mysite.com/project/'
39 #
40 # /usr/bin/python /usr/local/src/trac/contrib/trac-post-commit-hook \
41 # -p "$TRAC_ENV" \
42 # -r "$REV" \
43 # -u "$AUTHOR" \
44 # -m "$LOG" \
45 # -s "$TRAC_URL"
46 #
47 # It searches commit messages for text in the form of:
48 # command #1
49 # command #1, #2
50 # command #1 & #2
51 # command #1 and #2
52 #
53 # You can have more then one command in a message. The following commands
54 # are supported. There is more then one spelling for each command, to make
55 # this as user-friendly as possible.
56 #
57 # closes, fixes
58 # The specified issue numbers are closed with the contents of this
59 # commit message being added to it.
60 # references, refs, addresses, re
61 # The specified issue numbers are left in their current status, but
62 # the contents of this commit message are added to their notes.
63 #
64 # A fairly complicated example of what you can do is with a commit message
65 # of:
66 #
67 # Changed blah and foo to do this or that. Fixes #10 and #12, and refs #12.
68 #
69 # This will close #10 and #12, and add a note to #12.
70
71 import re
72 import os
73 import sys
74 import time
75
76 from trac.env import open_environment
77 from trac.ticket.notification import TicketNotifyEmail
78 from trac.ticket import Ticket
79 from trac.ticket.web_ui import TicketModule
80 # TODO: move grouped_changelog_entries to model.py
81 from trac.web.href import Href
82
83 try:
84 from optparse import OptionParser
85 except ImportError:
86 try:
87 from optik import OptionParser
88 except ImportError:
89 raise ImportError, 'Requires Python 2.3 or the Optik option parsing library.'
90
91 parser = OptionParser()
92 parser.add_option('-e', '--require-envelope', dest='env', default='',
93 help='Require commands to be enclosed in an envelope. If -e[], '
94 'then commands must be in the form of [closes #4]. Must '
95 'be two characters.')
96 parser.add_option('-p', '--project', dest='project',
97 help='Path to the Trac project.')
98 parser.add_option('-r', '--revision', dest='rev',
99 help='Repository revision number.')
100 parser.add_option('-u', '--user', dest='user',
101 help='The user who is responsible for this action')
102 parser.add_option('-m', '--msg', dest='msg',
103 help='The log message to search.')
104 parser.add_option('-s', '--siteurl', dest='url',
105 help='The base URL to the project\'s trac website (to which '
106 '/ticket/## is appended). If this is not specified, '
107 'the project URL from trac.ini will be used.')
108
109 (options, args) = parser.parse_args(sys.argv[1:])
110
111 if options.env:
112 leftEnv = '\\' + options.env[0]
113 rghtEnv = '\\' + options.env[1]
114 else:
115 leftEnv = ''
116 rghtEnv = ''
117
118 commandPattern = re.compile(leftEnv + r'(?P<action>[A-Za-z]*).?(?P<ticket>#[0-9]+(?:(?:[, &]*|[ ]?and[ ]?)#[0-9]+)*)' + rghtEnv)
119 ticketPattern = re.compile(r'#([0-9]*)')
120
121 class CommitHook:
122 _supported_cmds = {'close': '_cmdClose',
123 'closed': '_cmdClose',
124 'closes': '_cmdClose',
125 'fix': '_cmdClose',
126 'fixed': '_cmdClose',
127 'fixes': '_cmdClose',
128 'addresses': '_cmdRefs',
129 're': '_cmdRefs',
130 'references': '_cmdRefs',
131 'refs': '_cmdRefs',
132 'see': '_cmdRefs'}
133
134 def __init__(self, project=options.project, author=options.user,
135 rev=options.rev, msg=options.msg, url=options.url):
136 self.author = author
137 self.rev = rev
138 self.msg = "(In [%s]) %s" % (rev, msg)
139 self.now = int(time.time())
140 self.env = open_environment(project)
141 if url is None:
142 url = self.env.config.get('project', 'url')
143 class Request(object):
144 def __init__(self):
145 self.href = self.abs_href = Href(url)
146
147 cmdGroups = commandPattern.findall(msg)
148
149 tickets = {}
150 for cmd, tkts in cmdGroups:
151 funcname = CommitHook._supported_cmds.get(cmd.lower(), '')
152 if funcname:
153 for tkt_id in ticketPattern.findall(tkts):
154 func = getattr(self, funcname)
155 tickets.setdefault(tkt_id, []).append(func)
156
157 for tkt_id, cmds in tickets.iteritems():
158 try:
159 db = self.env.get_db_cnx()
160
161 ticket = Ticket(self.env, int(tkt_id), db)
162 for cmd in cmds:
163 cmd(ticket)
164
165 # determine sequence number...
166 cnum = 0
167 tm = TicketModule(self.env)
168 for change in tm.grouped_changelog_entries(ticket, db):
169 if change['permanent']:
170 cnum += 1
171
172 ticket.save_changes(self.author, self.msg, self.now, db, cnum+1)
173 db.commit()
174
175 tn = TicketNotifyEmail(self.env)
176 tn.notify(ticket, Request(), newticket=0, modtime=self.now)
177 except Exception, e:
178 # import traceback
179 # traceback.print_exc(file=sys.stderr)
180 print>>sys.stderr, 'Unexpected error while processing ticket ' \
181 'ID %s: %s' % (tkt_id, e)
182
183
184 def _cmdClose(self, ticket):
185 ticket['status'] = 'closed'
186 ticket['resolution'] = 'fixed'
187
188 def _cmdRefs(self, ticket):
189 pass
190
191
192 if __name__ == "__main__":
193 if len(sys.argv) < 5:
194 print "For usage: %s --help" % (sys.argv[0])
195 else:
196 CommitHook()
Copyright (C) 2012-2017 Edgewall Software