]>
git.rmz.io Git - dotfiles.git/blob - bin/svn-hook-postcommit-review
ef26c8e003d591f3fba61da3cb3b8b751be71e4e
3 # svn-hook-postcommit-review
4 # This script should be invoked from the subversion post-commit hook like this:
8 # /usr/bin/python /some/path/svn-hook-postcommit-review "$REPOS" "$REV" || exit 1
10 # Searches the commit message for text in the form of:
11 # publish review - publishes a review request
12 # draft review - creates a draft review request
14 # The space before 'review' may be ommitted.
16 # The log message is interpreted for review request parameters:
17 # summary = up to first period+space, first new-line, or 250 chars
18 # description = entire log message
19 # existing review updated if log message includes 'update review:[0-9]+'
20 # bugs added to review if log message includes commands as defined in
21 # supported_ticket_cmds
23 # By default, the review request is created out of a diff between the current
24 # revision (M) and the previous revision (M-1).
26 # To create a diff that spans multiple revisions, include
27 # 'after revision:[0-9]+' in the log message.
29 # To limit the diff to changes in a certain path (e.g. a branch), include
30 # 'base path:"<path>"' in the log message. The path must be relative to
31 # the root of the repository and be surrounded by single or double quotes.
33 # An example commit message is:
35 # Changed blah and foo to do this or that. Publish review ticket:1
36 # update review:2 after revision:3 base path:'internal/trunk/style'.
38 # This would update the existing review 2 with a diff of changes to files under
39 # the style directory between this commit and revision 3. It would place
40 # the entire log message in the review summary and description, and put
41 # bug id 1 in the bugs field.
43 # This script may only be run from outside a working copy.
47 # User configurable variables
50 # Path to post-review script
52 # Username and password for Review Board user that will be connecting
53 # to create all review requests. This user must have 'submit as'
54 # privileges, since it will submit requests in the name of svn committers.
56 PASSWORD
= 'TYxxcGm337FtubqN'
58 # If true, runs post-review in debug mode and outputs its diff
62 # end user configurable variables
73 # list of trac commands from trac-post-commit-hook.py.
74 # numbers following these commands will be added to the bugs
75 # field of the review request.
76 supported_ticket_cmds
= {'review': '_cmdReview',
77 'publishreview': '_cmdReview',
78 'publish review': '_cmdReview',
79 'draftreview': '_cmdReview',
80 'draft review': '_cmdReview'}
82 ticket_prefix
= '(?:#|(?:ticket|issue|bug)[: ]?)'
83 ticket_reference
= ticket_prefix
+ '[0-9]+'
84 ticket_command
= (r
'(?P<action>[A-Za-z]*).?'
85 '(?P<ticket>%s(?:(?:[, &]*|[ ]?and[ ]?)%s)*)' %
86 (ticket_reference
, ticket_reference
))
88 def execute(command
, env
=None, ignore_errors
=False):
90 Utility function to execute a command and return the output.
91 Derived from Review Board's post-review script.
94 env
.update(os
.environ
)
98 p
= subprocess
.Popen(command
,
99 stdin
= subprocess
.PIPE
,
100 stdout
= subprocess
.PIPE
,
101 stderr
= subprocess
.STDOUT
,
103 close_fds
= sys
.platform
.startswith('win'),
104 universal_newlines
= True,
106 data
= p
.stdout
.read()
108 if rc
and not ignore_errors
:
109 sys
.stderr
.write('Failed to execute command: %s\n%s\n' % (command
, data
))
115 if len(sys
.argv
) != 3:
116 sys
.stderr
.write('Usage: %s <repos> <rev>\n' % sys
.argv
[0])
122 # verify that rev parameter is an int
126 sys
.stderr
.write("Parameter <rev> must be an int, was given %s\n" % rev
)
129 # get the svn file system object
130 fs_ptr
= svn
.repos
.svn_repos_fs(svn
.repos
.svn_repos_open(
131 svn
.core
.svn_path_canonicalize(repos
)))
133 # get the log message
134 log
= svn
.fs
.svn_fs_revision_prop(fs_ptr
, int(rev
),
135 svn
.core
.SVN_PROP_REVISION_LOG
)
137 # error if log message is blank
138 if len(log
.strip()) < 1:
139 sys
.stderr
.write("Log message is empty, no review request created\n")
143 author
= svn
.fs
.svn_fs_revision_prop(fs_ptr
, int(rev
),
144 svn
.core
.SVN_PROP_REVISION_AUTHOR
)
146 # error if author is blank
147 if len(author
.strip()) < 1:
148 sys
.stderr
.write("Author is blank, no review request created\n")
151 # check whether to create a review, based on presence of word
152 # 'review' with prefix
153 review
= r
'(?:publish|draft)(?: )?review'
154 if not re
.search(review
, log
, re
.M | re
.I
):
155 print 'No review requested'
158 # check for update to existing review
159 m
= re
.search(r
'update(?: )?review:([0-9]+)', log
, re
.M | re
.I
)
161 reviewid
= '--review-request-id=' + m
.group(1)
165 # check whether to publish or leave review as draft
166 if re
.search(r
'draft(?: )?review', log
, re
.M | re
.I
):
171 # get previous revision number -- either 1 prior, or
172 # user-specified number
173 m
= re
.search(r
'after(?: )?revision:([0-9]+)', log
, re
.M | re
.I
)
177 prevrev
= int(rev
) - 1
179 # check for an explicitly-provided base path (must be contained
181 m
= re
.search(r
'base ?path:[\'"]([^\'"]+)[\'"]', log, re.M | re.I)
183 base_path = m.group(1)
187 # get bug numbers referenced in this log message
188 ticket_command_re = re.compile(ticket_command)
189 ticket_re = re.compile(ticket_prefix + '([0-9]+)')
192 ticket_cmd_groups = ticket_command_re.findall(log)
193 for cmd, tkts in ticket_cmd_groups:
194 funcname = supported_ticket_cmds.get(cmd.lower(), '')
196 for tkt_id in ticket_re.findall(tkts):
197 ticket_ids.append(tkt_id)
200 bugs = '--bugs-closed=' + ','.join(ticket_ids)
204 # summary is log up to first period+space / first new line / first 250 chars
205 # (whichever comes first)
206 summary = '--summary=' + log[:250].splitlines().pop(0).split('. ').pop(0)
208 # other parameters for postreview
209 repository_url = '--repository-url=file://' + repos
210 password = '--password=' + PASSWORD
211 username = '--username=' + USERNAME
212 description = "--description
=(In
[%s]) %s" % (rev, log)
213 submitas = '--submit-as=' + author
214 revision = '--revision-range=%s:%s' % (prevrev, rev)
217 args = [repository_url, username, password, publish,
218 submitas, revision, base_path, reviewid]
220 # filter out any potentially blank args, which will confuse post-review
221 args = [i for i in args if len(i) > 1]
223 # if not updating an existing review, add extra arguments
224 if len(reviewid) == 0:
225 args += [summary, description, bugs]
228 args += ['-d', '--output-diff']
229 print [os.path.join(POSTREVIEW_PATH, 'post-review')] + args
231 # Run Review Board post-review script
232 data = execute([os.path.join(POSTREVIEW_PATH, 'post-review')] + args,
233 env = {'LANG': 'en_US.UTF-8'})
238 if __name__ == '__main__':