events: added support for pull-request-comment and commit-comment events....
marcink -
r4314:9d74b996 default
Not Reviewed
Show More
Add another comment
TODOs: 0 unresolved 0 Resolved
COMMENTS: 0 General 0 Inline
@@ -0,0 +1,26
1 <div tal:define="css_class css_class|field.widget.css_class;
2 style style|field.widget.style;
3 oid oid|field.oid;
4 inline getattr(field.widget, 'inline', False)"
5 tal:omit-tag="not inline">
6 ${field.start_sequence()}
7 <div tal:repeat="choice values | field.widget.values"
8 tal:omit-tag="inline"
9 class="checkbox">
10 <div tal:define="(value, title, help_block) choice">
11 <input tal:attributes="checked value in cstruct;
12 class css_class;
13 style style"
14 type="checkbox"
15 name="checkbox"
16 value="${value}"
17 id="${oid}-${repeat.choice.index}"/>
18 <label for="${oid}-${repeat.choice.index}"
19 tal:attributes="class inline and 'checkbox-inline'">
20 ${title}
21 </label>
22 <p tal:condition="help_block" class="help-block">${help_block}</p>
23 </div>
24 </div>
25 ${field.end_sequence()}
26 </div>
@@ -75,4 +75,5 from rhodecode.events.pullrequest import
75 PullRequestReviewEvent,
75 PullRequestReviewEvent,
76 PullRequestMergeEvent,
76 PullRequestMergeEvent,
77 PullRequestCloseEvent,
77 PullRequestCloseEvent,
78 PullRequestCommentEvent,
78 )
79 )
@@ -44,6 +44,9 class RhodecodeEvent(object):
44 self._request = request
44 self._request = request
45 self.utc_timestamp = datetime.datetime.utcnow()
45 self.utc_timestamp = datetime.datetime.utcnow()
46
46
47 def __repr__(self):
48 return '<%s:(%s)>' % (self.__class__.__name__, self.name)
49
47 def get_request(self):
50 def get_request(self):
48 if self._request:
51 if self._request:
49 return self._request
52 return self._request
@@ -116,3 +119,4 class RhodeCodeIntegrationEvent(Rhodecod
116 """
119 """
117 Special subclass for Integration events
120 Special subclass for Integration events
118 """
121 """
122 description = ''
@@ -77,6 +77,7 class PullRequestCreateEvent(PullRequest
77 """
77 """
78 name = 'pullrequest-create'
78 name = 'pullrequest-create'
79 display_name = lazy_ugettext('pullrequest created')
79 display_name = lazy_ugettext('pullrequest created')
80 description = lazy_ugettext('Event triggered after pull request was created')
80
81
81
82
82 class PullRequestCloseEvent(PullRequestEvent):
83 class PullRequestCloseEvent(PullRequestEvent):
@@ -86,6 +87,7 class PullRequestCloseEvent(PullRequestE
86 """
87 """
87 name = 'pullrequest-close'
88 name = 'pullrequest-close'
88 display_name = lazy_ugettext('pullrequest closed')
89 display_name = lazy_ugettext('pullrequest closed')
90 description = lazy_ugettext('Event triggered after pull request was closed')
89
91
90
92
91 class PullRequestUpdateEvent(PullRequestEvent):
93 class PullRequestUpdateEvent(PullRequestEvent):
@@ -95,6 +97,7 class PullRequestUpdateEvent(PullRequest
95 """
97 """
96 name = 'pullrequest-update'
98 name = 'pullrequest-update'
97 display_name = lazy_ugettext('pullrequest commits updated')
99 display_name = lazy_ugettext('pullrequest commits updated')
100 description = lazy_ugettext('Event triggered after pull requests was updated')
98
101
99
102
100 class PullRequestReviewEvent(PullRequestEvent):
103 class PullRequestReviewEvent(PullRequestEvent):
@@ -104,6 +107,8 class PullRequestReviewEvent(PullRequest
104 """
107 """
105 name = 'pullrequest-review'
108 name = 'pullrequest-review'
106 display_name = lazy_ugettext('pullrequest review changed')
109 display_name = lazy_ugettext('pullrequest review changed')
110 description = lazy_ugettext('Event triggered after a review status of a '
111 'pull requests has changed to other.')
107
112
108 def __init__(self, pullrequest, status):
113 def __init__(self, pullrequest, status):
109 super(PullRequestReviewEvent, self).__init__(pullrequest)
114 super(PullRequestReviewEvent, self).__init__(pullrequest)
@@ -117,6 +122,8 class PullRequestMergeEvent(PullRequestE
117 """
122 """
118 name = 'pullrequest-merge'
123 name = 'pullrequest-merge'
119 display_name = lazy_ugettext('pullrequest merged')
124 display_name = lazy_ugettext('pullrequest merged')
125 description = lazy_ugettext('Event triggered after a successful merge operation '
126 'was executed on a pull request')
120
127
121
128
122 class PullRequestCommentEvent(PullRequestEvent):
129 class PullRequestCommentEvent(PullRequestEvent):
@@ -126,6 +133,8 class PullRequestCommentEvent(PullReques
126 """
133 """
127 name = 'pullrequest-comment'
134 name = 'pullrequest-comment'
128 display_name = lazy_ugettext('pullrequest commented')
135 display_name = lazy_ugettext('pullrequest commented')
136 description = lazy_ugettext('Event triggered after a comment was made on a code '
137 'in the pull request')
129
138
130 def __init__(self, pullrequest, comment):
139 def __init__(self, pullrequest, comment):
131 super(PullRequestCommentEvent, self).__init__(pullrequest)
140 super(PullRequestCommentEvent, self).__init__(pullrequest)
@@ -186,13 +186,33 class RepoCommitCommentEvent(RepoEvent):
186 An instance of this class is emitted as an :term:`event` after a comment is made
186 An instance of this class is emitted as an :term:`event` after a comment is made
187 on repository commit.
187 on repository commit.
188 """
188 """
189
190 name = 'repo-commit-comment'
191 display_name = lazy_ugettext('repository commit comment')
192 description = lazy_ugettext('Event triggered after a comment was made '
193 'on commit inside a repository')
194
189 def __init__(self, repo, commit, comment):
195 def __init__(self, repo, commit, comment):
190 super(RepoCommitCommentEvent, self).__init__(repo)
196 super(RepoCommitCommentEvent, self).__init__(repo)
191 self.commit = commit
197 self.commit = commit
192 self.comment = comment
198 self.comment = comment
193
199
194 name = 'repo-commit-comment'
200 def as_dict(self):
195 display_name = lazy_ugettext('repository commit comment')
201 data = super(RepoCommitCommentEvent, self).as_dict()
202 data['commit'] = {
203 'commit_id': self.commit.raw_id,
204 'commit_message': self.commit.message,
205 'commit_branch': self.commit.branch,
206 }
207
208 data['comment'] = {
209 'comment_id': self.comment.comment_id,
210 'comment_text': self.comment.text,
211 'comment_type': self.comment.comment_type,
212 'comment_f_path': self.comment.f_path,
213 'comment_line_no': self.comment.line_no,
214 }
215 return data
196
216
197
217
198 class RepoPreCreateEvent(RepoEvent):
218 class RepoPreCreateEvent(RepoEvent):
@@ -202,6 +222,7 class RepoPreCreateEvent(RepoEvent):
202 """
222 """
203 name = 'repo-pre-create'
223 name = 'repo-pre-create'
204 display_name = lazy_ugettext('repository pre create')
224 display_name = lazy_ugettext('repository pre create')
225 description = lazy_ugettext('Event triggered before repository is created')
205
226
206
227
207 class RepoCreateEvent(RepoEvent):
228 class RepoCreateEvent(RepoEvent):
@@ -211,6 +232,7 class RepoCreateEvent(RepoEvent):
211 """
232 """
212 name = 'repo-create'
233 name = 'repo-create'
213 display_name = lazy_ugettext('repository created')
234 display_name = lazy_ugettext('repository created')
235 description = lazy_ugettext('Event triggered after repository was created')
214
236
215
237
216 class RepoPreDeleteEvent(RepoEvent):
238 class RepoPreDeleteEvent(RepoEvent):
@@ -220,6 +242,7 class RepoPreDeleteEvent(RepoEvent):
220 """
242 """
221 name = 'repo-pre-delete'
243 name = 'repo-pre-delete'
222 display_name = lazy_ugettext('repository pre delete')
244 display_name = lazy_ugettext('repository pre delete')
245 description = lazy_ugettext('Event triggered before a repository is deleted')
223
246
224
247
225 class RepoDeleteEvent(RepoEvent):
248 class RepoDeleteEvent(RepoEvent):
@@ -229,6 +252,7 class RepoDeleteEvent(RepoEvent):
229 """
252 """
230 name = 'repo-delete'
253 name = 'repo-delete'
231 display_name = lazy_ugettext('repository deleted')
254 display_name = lazy_ugettext('repository deleted')
255 description = lazy_ugettext('Event triggered after repository was deleted')
232
256
233
257
234 class RepoVCSEvent(RepoEvent):
258 class RepoVCSEvent(RepoEvent):
@@ -269,6 +293,7 class RepoPrePullEvent(RepoVCSEvent):
269 """
293 """
270 name = 'repo-pre-pull'
294 name = 'repo-pre-pull'
271 display_name = lazy_ugettext('repository pre pull')
295 display_name = lazy_ugettext('repository pre pull')
296 description = lazy_ugettext('Event triggered before repository code is pulled')
272
297
273
298
274 class RepoPullEvent(RepoVCSEvent):
299 class RepoPullEvent(RepoVCSEvent):
@@ -278,6 +303,7 class RepoPullEvent(RepoVCSEvent):
278 """
303 """
279 name = 'repo-pull'
304 name = 'repo-pull'
280 display_name = lazy_ugettext('repository pull')
305 display_name = lazy_ugettext('repository pull')
306 description = lazy_ugettext('Event triggered after repository code was pulled')
281
307
282
308
283 class RepoPrePushEvent(RepoVCSEvent):
309 class RepoPrePushEvent(RepoVCSEvent):
@@ -287,6 +313,8 class RepoPrePushEvent(RepoVCSEvent):
287 """
313 """
288 name = 'repo-pre-push'
314 name = 'repo-pre-push'
289 display_name = lazy_ugettext('repository pre push')
315 display_name = lazy_ugettext('repository pre push')
316 description = lazy_ugettext('Event triggered before the code is '
317 'pushed to a repository')
290
318
291
319
292 class RepoPushEvent(RepoVCSEvent):
320 class RepoPushEvent(RepoVCSEvent):
@@ -298,6 +326,8 class RepoPushEvent(RepoVCSEvent):
298 """
326 """
299 name = 'repo-push'
327 name = 'repo-push'
300 display_name = lazy_ugettext('repository push')
328 display_name = lazy_ugettext('repository push')
329 description = lazy_ugettext('Event triggered after the code was '
330 'pushed to a repository')
301
331
302 def __init__(self, repo_name, pushed_commit_ids, extras):
332 def __init__(self, repo_name, pushed_commit_ids, extras):
303 super(RepoPushEvent, self).__init__(repo_name, extras)
333 super(RepoPushEvent, self).__init__(repo_name, extras)
@@ -60,6 +60,7 class RepoGroupCreateEvent(RepoGroupEven
60 """
60 """
61 name = 'repo-group-create'
61 name = 'repo-group-create'
62 display_name = lazy_ugettext('repository group created')
62 display_name = lazy_ugettext('repository group created')
63 description = lazy_ugettext('Event triggered after a repository group was created')
63
64
64
65
65 class RepoGroupDeleteEvent(RepoGroupEvent):
66 class RepoGroupDeleteEvent(RepoGroupEvent):
@@ -69,6 +70,7 class RepoGroupDeleteEvent(RepoGroupEven
69 """
70 """
70 name = 'repo-group-delete'
71 name = 'repo-group-delete'
71 display_name = lazy_ugettext('repository group deleted')
72 display_name = lazy_ugettext('repository group deleted')
73 description = lazy_ugettext('Event triggered after a repository group was deleted')
72
74
73
75
74 class RepoGroupUpdateEvent(RepoGroupEvent):
76 class RepoGroupUpdateEvent(RepoGroupEvent):
@@ -78,3 +80,4 class RepoGroupUpdateEvent(RepoGroupEven
78 """
80 """
79 name = 'repo-group-update'
81 name = 'repo-group-update'
80 display_name = lazy_ugettext('repository group update')
82 display_name = lazy_ugettext('repository group update')
83 description = lazy_ugettext('Event triggered after a repository group was updated')
@@ -125,6 +125,19 class IntegrationTypeBase(object):
125 """
125 """
126 return colander.Schema()
126 return colander.Schema()
127
127
128 def event_enabled(self, event):
129 """
130 Checks if submitted event is enabled based on the plugin settings
131 :param event:
132 :return: bool
133 """
134 allowed_events = self.settings['events']
135 if event.name not in allowed_events:
136 log.debug('event ignored: %r event %s not in allowed set of events %s',
137 event, event.name, allowed_events)
138 return False
139 return True
140
128
141
129 class EEIntegration(IntegrationTypeBase):
142 class EEIntegration(IntegrationTypeBase):
130 description = 'Integration available in RhodeCode EE edition.'
143 description = 'Integration available in RhodeCode EE edition.'
@@ -139,30 +152,57 class EEIntegration(IntegrationTypeBase)
139 # Helpers #
152 # Helpers #
140 # updating this required to update the `common_vars` as well.
153 # updating this required to update the `common_vars` as well.
141 WEBHOOK_URL_VARS = [
154 WEBHOOK_URL_VARS = [
142 ('event_name', 'Unique name of the event type, e.g pullrequest-update'),
155 # GENERAL
143 ('repo_name', 'Full name of the repository'),
156 ('General', [
144 ('repo_type', 'VCS type of repository'),
157 ('event_name', 'Unique name of the event type, e.g pullrequest-update'),
145 ('repo_id', 'Unique id of repository'),
158 ('repo_name', 'Full name of the repository'),
146 ('repo_url', 'Repository url'),
159 ('repo_type', 'VCS type of repository'),
160 ('repo_id', 'Unique id of repository'),
161 ('repo_url', 'Repository url'),
162 ]
163 ),
147 # extra repo fields
164 # extra repo fields
148 ('extra:<extra_key_name>', 'Extra repo variables, read from its settings.'),
165 ('Repository', [
149
166 ('extra:<extra_key_name>', 'Extra repo variables, read from its settings.'),
167 ]
168 ),
150 # special attrs below that we handle, using multi-call
169 # special attrs below that we handle, using multi-call
151 ('branch', 'Name of each branch submitted, if any.'),
170 ('Commit push - Multicalls', [
152 ('branch_head', 'Head ID of pushed branch (full sha of last commit), if any.'),
171 ('branch', 'Name of each branch submitted, if any.'),
153 ('commit_id', 'ID (full sha) of each commit submitted, if any.'),
172 ('branch_head', 'Head ID of pushed branch (full sha of last commit), if any.'),
154
173 ('commit_id', 'ID (full sha) of each commit submitted, if any.'),
174 ]
175 ),
155 # pr events vars
176 # pr events vars
156 ('pull_request_id', 'Unique ID of the pull request.'),
177 ('Pull request', [
157 ('pull_request_title', 'Title of the pull request.'),
178 ('pull_request_id', 'Unique ID of the pull request.'),
158 ('pull_request_url', 'Pull request url.'),
179 ('pull_request_title', 'Title of the pull request.'),
159 ('pull_request_shadow_url', 'Pull request shadow repo clone url.'),
180 ('pull_request_url', 'Pull request url.'),
160 ('pull_request_commits_uid', 'Calculated UID of all commits inside the PR. '
181 ('pull_request_shadow_url', 'Pull request shadow repo clone url.'),
161 'Changes after PR update'),
182 ('pull_request_commits_uid', 'Calculated UID of all commits inside the PR. '
183 'Changes after PR update'),
184 ]
185 ),
186 # commit comment event vars
187 ('Commit comment', [
188 ('commit_comment_id', 'Unique ID of the comment made on a commit.'),
189 ('commit_comment_text', 'Text of commit comment.'),
190 ('commit_comment_type', 'Type of comment, e.g note/todo.'),
162
191
192 ('commit_comment_f_path', 'Optionally path of file for inline comments.'),
193 ('commit_comment_line_no', 'Line number of the file: eg o10, or n200'),
194
195 ('commit_comment_commit_id', 'Commit id that comment was left at.'),
196 ('commit_comment_commit_branch', 'Commit branch that comment was left at'),
197 ('commit_comment_commit_message', 'Commit message that comment was left at'),
198 ]
199 ),
163 # user who triggers the call
200 # user who triggers the call
164 ('username', 'User who triggered the call.'),
201 ('Caller', [
165 ('user_id', 'User id who triggered the call.'),
202 ('username', 'User who triggered the call.'),
203 ('user_id', 'User id who triggered the call.'),
204 ]
205 ),
166 ]
206 ]
167
207
168 # common vars for url template used for CI plugins. Shared with webhook
208 # common vars for url template used for CI plugins. Shared with webhook
@@ -271,6 +311,26 class WebhookDataHandler(CommitParsingDa
271
311
272 return url_calls
312 return url_calls
273
313
314 def repo_commit_comment_handler(self, event, data):
315 url = self.get_base_parsed_template(data)
316 log.debug('register %s call(%s) to url %s', self.name, event, url)
317 comment_vars = [
318 ('commit_comment_id', data['comment']['comment_id']),
319 ('commit_comment_text', data['comment']['comment_text']),
320 ('commit_comment_type', data['comment']['comment_type']),
321
322 ('commit_comment_f_path', data['comment']['comment_f_path']),
323 ('commit_comment_line_no', data['comment']['comment_line_no']),
324
325 ('commit_comment_commit_id', data['commit']['commit_id']),
326 ('commit_comment_commit_branch', data['commit']['commit_branch']),
327 ('commit_comment_commit_message', data['commit']['commit_message']),
328 ]
329 for k, v in comment_vars:
330 url = UrlTmpl(url).safe_substitute(**{k: v})
331
332 return [(url, self.headers, data)]
333
274 def repo_create_event_handler(self, event, data):
334 def repo_create_event_handler(self, event, data):
275 url = self.get_base_parsed_template(data)
335 url = self.get_base_parsed_template(data)
276 log.debug('register %s call(%s) to url %s', self.name, event, url)
336 log.debug('register %s call(%s) to url %s', self.name, event, url)
@@ -298,12 +358,13 class WebhookDataHandler(CommitParsingDa
298 return self.repo_push_event_handler(event, data)
358 return self.repo_push_event_handler(event, data)
299 elif isinstance(event, events.RepoCreateEvent):
359 elif isinstance(event, events.RepoCreateEvent):
300 return self.repo_create_event_handler(event, data)
360 return self.repo_create_event_handler(event, data)
361 elif isinstance(event, events.RepoCommitCommentEvent):
362 return self.repo_commit_comment_handler(event, data)
301 elif isinstance(event, events.PullRequestEvent):
363 elif isinstance(event, events.PullRequestEvent):
302 return self.pull_request_event_handler(event, data)
364 return self.pull_request_event_handler(event, data)
303 else:
365 else:
304 raise ValueError(
366 raise ValueError(
305 'event type `%s` not in supported list: %s' % (
367 'event type `{}` has no handler defined'.format(event.__class__))
306 event.__class__, events))
307
368
308
369
309 def get_auth(settings):
370 def get_auth(settings):
@@ -320,9 +381,13 def get_web_token(settings):
320
381
321
382
322 def get_url_vars(url_vars):
383 def get_url_vars(url_vars):
323 return '\n'.join(
384 items = []
324 '{} - {}'.format('${' + key + '}', explanation)
385
325 for key, explanation in url_vars)
386 for section, section_items in url_vars:
387 items.append('\n*{}*'.format(section))
388 for key, explanation in section_items:
389 items.append(' {} - {}'.format('${' + key + '}', explanation))
390 return '\n'.join(items)
326
391
327
392
328 def render_with_traceback(template, *args, **kwargs):
393 def render_with_traceback(template, *args, **kwargs):
@@ -19,13 +19,14
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 from __future__ import unicode_literals
21 from __future__ import unicode_literals
22 import deform
23 import logging
22 import logging
23
24 import colander
24 import colander
25
25 import deform.widget
26 from mako.template import Template
26 from mako.template import Template
27
27
28 from rhodecode import events
28 from rhodecode import events
29 from rhodecode.model.validation_schema.widgets import CheckboxChoiceWidgetDesc
29 from rhodecode.translation import _
30 from rhodecode.translation import _
30 from rhodecode.lib.celerylib import run_task
31 from rhodecode.lib.celerylib import run_task
31 from rhodecode.lib.celerylib import tasks
32 from rhodecode.lib.celerylib import tasks
@@ -174,6 +175,10 class EmailIntegrationType(IntegrationTy
174 display_name = _('Email')
175 display_name = _('Email')
175 description = _('Send repo push summaries to a list of recipients via email')
176 description = _('Send repo push summaries to a list of recipients via email')
176
177
178 valid_events = [
179 events.RepoPushEvent
180 ]
181
177 @classmethod
182 @classmethod
178 def icon(cls):
183 def icon(cls):
179 return '''
184 return '''
@@ -240,59 +245,86 class EmailIntegrationType(IntegrationTy
240
245
241 def settings_schema(self):
246 def settings_schema(self):
242 schema = EmailSettingsSchema()
247 schema = EmailSettingsSchema()
248 schema.add(colander.SchemaNode(
249 colander.Set(),
250 widget=CheckboxChoiceWidgetDesc(
251 values=sorted(
252 [(e.name, e.display_name, e.description) for e in self.valid_events]
253 ),
254 ),
255 description="List of events activated for this integration",
256 name='events'
257 ))
243 return schema
258 return schema
244
259
245 def send_event(self, event):
260 def send_event(self, event):
246 data = event.as_dict()
261 log.debug('handling event %s with integration %s', event.name, self)
247 log.debug('got event: %r', event)
262
263 if event.__class__ not in self.valid_events:
264 log.debug('event %r not present in valid event list (%s)', event, self.valid_events)
265 return
266
267 if not self.event_enabled(event):
268 # NOTE(marcink): for legacy reasons we're skipping this check...
269 # since the email event haven't had any settings...
270 pass
248
271
272 handler = EmailEventHandler(self.settings)
273 handler(event, event_data=event.as_dict())
274
275
276 class EmailEventHandler(object):
277 def __init__(self, integration_settings):
278 self.integration_settings = integration_settings
279
280 def __call__(self, event, event_data):
249 if isinstance(event, events.RepoPushEvent):
281 if isinstance(event, events.RepoPushEvent):
250 repo_push_handler(data, self.settings)
282 self.repo_push_handler(event, event_data)
251 else:
283 else:
252 log.debug('ignoring event: %r', event)
284 log.debug('ignoring event: %r', event)
253
285
254
286 def repo_push_handler(self, event, data):
255 def repo_push_handler(data, settings):
287 commit_num = len(data['push']['commits'])
256 commit_num = len(data['push']['commits'])
288 server_url = data['server_url']
257 server_url = data['server_url']
258
289
259 if commit_num == 1:
290 if commit_num == 1:
260 if data['push']['branches']:
291 if data['push']['branches']:
261 _subject = '[{repo_name}] {author} pushed {commit_num} commit on branches: {branches}'
292 _subject = '[{repo_name}] {author} pushed {commit_num} commit on branches: {branches}'
262 else:
293 else:
263 _subject = '[{repo_name}] {author} pushed {commit_num} commit'
294 _subject = '[{repo_name}] {author} pushed {commit_num} commit'
264 subject = _subject.format(
295 subject = _subject.format(
265 author=data['actor']['username'],
296 author=data['actor']['username'],
266 repo_name=data['repo']['repo_name'],
297 repo_name=data['repo']['repo_name'],
267 commit_num=commit_num,
298 commit_num=commit_num,
268 branches=', '.join(
299 branches=', '.join(
269 branch['name'] for branch in data['push']['branches'])
300 branch['name'] for branch in data['push']['branches'])
270 )
301 )
271 else:
272 if data['push']['branches']:
273 _subject = '[{repo_name}] {author} pushed {commit_num} commits on branches: {branches}'
274 else:
302 else:
275 _subject = '[{repo_name}] {author} pushed {commit_num} commits'
303 if data['push']['branches']:
276 subject = _subject.format(
304 _subject = '[{repo_name}] {author} pushed {commit_num} commits on branches: {branches}'
277 author=data['actor']['username'],
305 else:
278 repo_name=data['repo']['repo_name'],
306 _subject = '[{repo_name}] {author} pushed {commit_num} commits'
279 commit_num=commit_num,
307 subject = _subject.format(
280 branches=', '.join(
308 author=data['actor']['username'],
281 branch['name'] for branch in data['push']['branches']))
309 repo_name=data['repo']['repo_name'],
310 commit_num=commit_num,
311 branches=', '.join(
312 branch['name'] for branch in data['push']['branches']))
282
313
283 email_body_plaintext = render_with_traceback(
314 email_body_plaintext = render_with_traceback(
284 REPO_PUSH_TEMPLATE_PLAINTEXT,
315 REPO_PUSH_TEMPLATE_PLAINTEXT,
285 data=data,
316 data=data,
286 subject=subject,
317 subject=subject,
287 instance_url=server_url)
318 instance_url=server_url)
288
319
289 email_body_html = render_with_traceback(
320 email_body_html = render_with_traceback(
290 REPO_PUSH_TEMPLATE_HTML,
321 REPO_PUSH_TEMPLATE_HTML,
291 data=data,
322 data=data,
292 subject=subject,
323 subject=subject,
293 instance_url=server_url)
324 instance_url=server_url)
294
325
295 for email_address in settings['recipients']:
326 recipients = self.integration_settings['recipients']
296 run_task(
327 for email_address in recipients:
297 tasks.send_email, email_address, subject,
328 run_task(
298 email_body_plaintext, email_body_html)
329 tasks.send_email, email_address, subject,
330 email_body_plaintext, email_body_html)
@@ -26,6 +26,7 import colander
26 import textwrap
26 import textwrap
27 from mako.template import Template
27 from mako.template import Template
28 from rhodecode import events
28 from rhodecode import events
29 from rhodecode.model.validation_schema.widgets import CheckboxChoiceWidgetDesc
29 from rhodecode.translation import _
30 from rhodecode.translation import _
30 from rhodecode.lib import helpers as h
31 from rhodecode.lib import helpers as h
31 from rhodecode.lib.celerylib import run_task, async_task, RequestContextTask
32 from rhodecode.lib.celerylib import run_task, async_task, RequestContextTask
@@ -119,13 +120,10 class HipchatIntegrationType(Integration
119
120
120 def send_event(self, event):
121 def send_event(self, event):
121 if event.__class__ not in self.valid_events:
122 if event.__class__ not in self.valid_events:
122 log.debug('event not valid: %r', event)
123 log.debug('event %r not present in valid event list (%s)', event, self.valid_events)
123 return
124 return
124
125
125 allowed_events = self.settings['events']
126 if not self.event_enabled(event):
126 if event.name not in allowed_events:
127 log.debug('event ignored: %r event %s not in allowed events %s',
128 event, event.name, allowed_events)
129 return
127 return
130
128
131 data = event.as_dict()
129 data = event.as_dict()
@@ -133,8 +131,6 class HipchatIntegrationType(Integration
133 text = '<b>%s<b> caused a <b>%s</b> event' % (
131 text = '<b>%s<b> caused a <b>%s</b> event' % (
134 data['actor']['username'], event.name)
132 data['actor']['username'], event.name)
135
133
136 log.debug('handling hipchat event for %s', event.name)
137
138 if isinstance(event, events.PullRequestCommentEvent):
134 if isinstance(event, events.PullRequestCommentEvent):
139 text = self.format_pull_request_comment_event(event, data)
135 text = self.format_pull_request_comment_event(event, data)
140 elif isinstance(event, events.PullRequestReviewEvent):
136 elif isinstance(event, events.PullRequestReviewEvent):
@@ -154,12 +150,12 class HipchatIntegrationType(Integration
154 schema = HipchatSettingsSchema()
150 schema = HipchatSettingsSchema()
155 schema.add(colander.SchemaNode(
151 schema.add(colander.SchemaNode(
156 colander.Set(),
152 colander.Set(),
157 widget=deform.widget.CheckboxChoiceWidget(
153 widget=CheckboxChoiceWidgetDesc(
158 values=sorted(
154 values=sorted(
159 [(e.name, e.display_name) for e in self.valid_events]
155 [(e.name, e.display_name, e.description) for e in self.valid_events]
160 )
156 ),
161 ),
157 ),
162 description="Events activated for this integration",
158 description="List of events activated for this integration",
163 name='events'
159 name='events'
164 ))
160 ))
165
161
@@ -30,6 +30,7 import colander
30 from mako.template import Template
30 from mako.template import Template
31
31
32 from rhodecode import events
32 from rhodecode import events
33 from rhodecode.model.validation_schema.widgets import CheckboxChoiceWidgetDesc
33 from rhodecode.translation import _
34 from rhodecode.translation import _
34 from rhodecode.lib import helpers as h
35 from rhodecode.lib import helpers as h
35 from rhodecode.lib.celerylib import run_task, async_task, RequestContextTask
36 from rhodecode.lib.celerylib import run_task, async_task, RequestContextTask
@@ -134,14 +135,13 class SlackIntegrationType(IntegrationTy
134 ]
135 ]
135
136
136 def send_event(self, event):
137 def send_event(self, event):
138 log.debug('handling event %s with integration %s', event.name, self)
139
137 if event.__class__ not in self.valid_events:
140 if event.__class__ not in self.valid_events:
138 log.debug('event not valid: %r', event)
141 log.debug('event %r not present in valid event list (%s)', event, self.valid_events)
139 return
142 return
140
143
141 allowed_events = self.settings['events']
144 if not self.event_enabled(event):
142 if event.name not in allowed_events:
143 log.debug('event ignored: %r event %s not in allowed events %s',
144 event, event.name, allowed_events)
145 return
145 return
146
146
147 data = event.as_dict()
147 data = event.as_dict()
@@ -154,8 +154,6 class SlackIntegrationType(IntegrationTy
154 fields = None
154 fields = None
155 overrides = None
155 overrides = None
156
156
157 log.debug('handling slack event for %s', event.name)
158
159 if isinstance(event, events.PullRequestCommentEvent):
157 if isinstance(event, events.PullRequestCommentEvent):
160 (title, text, fields, overrides) \
158 (title, text, fields, overrides) \
161 = self.format_pull_request_comment_event(event, data)
159 = self.format_pull_request_comment_event(event, data)
@@ -176,12 +174,12 class SlackIntegrationType(IntegrationTy
176 schema = SlackSettingsSchema()
174 schema = SlackSettingsSchema()
177 schema.add(colander.SchemaNode(
175 schema.add(colander.SchemaNode(
178 colander.Set(),
176 colander.Set(),
179 widget=deform.widget.CheckboxChoiceWidget(
177 widget=CheckboxChoiceWidgetDesc(
180 values=sorted(
178 values=sorted(
181 [(e.name, e.display_name) for e in self.valid_events]
179 [(e.name, e.display_name, e.description) for e in self.valid_events]
182 )
180 ),
183 ),
181 ),
184 description="Events activated for this integration",
182 description="List of events activated for this integration",
185 name='events'
183 name='events'
186 ))
184 ))
187
185
@@ -20,13 +20,14
20
20
21 from __future__ import unicode_literals
21 from __future__ import unicode_literals
22
22
23 import deform
24 import deform.widget
23 import deform.widget
25 import logging
24 import logging
26 import colander
25 import colander
27
26
28 import rhodecode
27 import rhodecode
29 from rhodecode import events