Show More
@@ -128,6 +128,9 b' class PullRequestCommentEvent(PullReques' | |||
|
128 | 128 | 'comment': { |
|
129 | 129 | 'status': status, |
|
130 | 130 | 'text': self.comment.text, |
|
131 | 'type': self.comment.comment_type, | |
|
132 | 'file': self.comment.f_path, | |
|
133 | 'line': self.comment.line_no, | |
|
131 | 134 | 'url': CommentsModel().get_url(self.comment) |
|
132 | 135 | } |
|
133 | 136 | }) |
@@ -34,10 +34,9 b' def _commits_as_dict(commit_ids, repos):' | |||
|
34 | 34 | :param repos: list of repos to check |
|
35 | 35 | """ |
|
36 | 36 | from rhodecode.lib.utils2 import extract_mentioned_users |
|
37 | from rhodecode.model.db import Repository | |
|
38 | 37 | from rhodecode.lib import helpers as h |
|
39 |
from rhodecode.lib.helpers import |
|
|
40 | from rhodecode.lib.helpers import urlify_commit_message | |
|
38 | from rhodecode.lib.helpers import ( | |
|
39 | urlify_commit_message, process_patterns, chop_at_smart) | |
|
41 | 40 | |
|
42 | 41 | if not repos: |
|
43 | 42 | raise Exception('no repo defined') |
@@ -78,14 +77,15 b' def _commits_as_dict(commit_ids, repos):' | |||
|
78 | 77 | cs_data['issues'] = issues_data |
|
79 | 78 | cs_data['message_html'] = urlify_commit_message(cs_data['message'], |
|
80 | 79 | repo.repo_name) |
|
80 | cs_data['message_html_title'] = chop_at_smart(cs_data['message'], '\n', suffix_if_chopped='...') | |
|
81 | 81 | commits.append(cs_data) |
|
82 | 82 | |
|
83 | 83 | needed_commits.remove(commit_id) |
|
84 | 84 | |
|
85 | 85 | except Exception as e: |
|
86 | 86 | log.exception(e) |
|
87 |
# we don't send any commits when crash happens, only full list |
|
|
88 | # we short circuit then. | |
|
87 | # we don't send any commits when crash happens, only full list | |
|
88 | # matters we short circuit then. | |
|
89 | 89 | return [] |
|
90 | 90 | |
|
91 | 91 | missing_commits = set(commit_ids) - set(c['raw_id'] for c in commits) |
@@ -19,12 +19,14 b'' | |||
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | 21 | from __future__ import unicode_literals |
|
22 | import re | |
|
23 | import time | |
|
24 | import textwrap | |
|
25 | import logging | |
|
26 | ||
|
22 | 27 | import deform |
|
23 | import re | |
|
24 | import logging | |
|
25 | 28 | import requests |
|
26 | 29 | import colander |
|
27 | import textwrap | |
|
28 | 30 | from celery.task import task |
|
29 | 31 | from mako.template import Template |
|
30 | 32 | |
@@ -85,17 +87,6 b' class SlackSettingsSchema(colander.Schem' | |||
|
85 | 87 | ) |
|
86 | 88 | |
|
87 | 89 | |
|
88 | repo_push_template = Template(r''' | |
|
89 | *${data['actor']['username']}* pushed to repo <${data['repo']['url']}|${data['repo']['repo_name']}>: | |
|
90 | %for branch, branch_commits in branches_commits.items(): | |
|
91 | branch: <${branch_commits['branch']['url']}|${branch_commits['branch']['name']}> | |
|
92 | %for commit in branch_commits['commits']: | |
|
93 | > <${commit['url']}|${commit['short_id']}> - ${commit['message_html']|html_to_slack_links} | |
|
94 | %endfor | |
|
95 | %endfor | |
|
96 | ''') | |
|
97 | ||
|
98 | ||
|
99 | 90 | class SlackIntegrationType(IntegrationTypeBase): |
|
100 | 91 | key = 'slack' |
|
101 | 92 | display_name = _('Slack') |
@@ -124,25 +115,31 b' class SlackIntegrationType(IntegrationTy' | |||
|
124 | 115 | |
|
125 | 116 | data = event.as_dict() |
|
126 | 117 | |
|
118 | # defaults | |
|
119 | title = '*%s* caused a *%s* event' % ( | |
|
120 | data['actor']['username'], event.name) | |
|
127 | 121 | text = '*%s* caused a *%s* event' % ( |
|
128 | 122 | data['actor']['username'], event.name) |
|
123 | fields = None | |
|
124 | overrides = None | |
|
129 | 125 | |
|
130 | 126 | log.debug('handling slack event for %s' % event.name) |
|
131 | 127 | |
|
132 | 128 | if isinstance(event, events.PullRequestCommentEvent): |
|
133 | text = self.format_pull_request_comment_event(event, data) | |
|
129 | (title, text, fields, overrides) \ | |
|
130 | = self.format_pull_request_comment_event(event, data) | |
|
134 | 131 | elif isinstance(event, events.PullRequestReviewEvent): |
|
135 | text = self.format_pull_request_review_event(event, data) | |
|
132 | title, text = self.format_pull_request_review_event(event, data) | |
|
136 | 133 | elif isinstance(event, events.PullRequestEvent): |
|
137 | text = self.format_pull_request_event(event, data) | |
|
134 | title, text = self.format_pull_request_event(event, data) | |
|
138 | 135 | elif isinstance(event, events.RepoPushEvent): |
|
139 | text = self.format_repo_push_event(data) | |
|
136 | title, text = self.format_repo_push_event(data) | |
|
140 | 137 | elif isinstance(event, events.RepoCreateEvent): |
|
141 | text = self.format_repo_create_event(data) | |
|
138 | title, text = self.format_repo_create_event(data) | |
|
142 | 139 | else: |
|
143 | 140 | log.error('unhandled event type: %r' % event) |
|
144 | 141 | |
|
145 | run_task(post_text_to_slack, self.settings, text) | |
|
142 | run_task(post_text_to_slack, self.settings, title, text, fields, overrides) | |
|
146 | 143 | |
|
147 | 144 | def settings_schema(self): |
|
148 | 145 | schema = SlackSettingsSchema() |
@@ -167,37 +164,60 b' class SlackIntegrationType(IntegrationTy' | |||
|
167 | 164 | comment_url=data['comment']['url'], |
|
168 | 165 | ) |
|
169 | 166 | |
|
170 | comment_status = '' | |
|
167 | fields = None | |
|
168 | overrides = None | |
|
169 | status_text = None | |
|
170 | ||
|
171 | 171 | if data['comment']['status']: |
|
172 | comment_status = '[{}]: '.format(data['comment']['status']) | |
|
172 | status_color = { | |
|
173 | 'approved': '#0ac878', | |
|
174 | 'rejected': '#e85e4d'}.get(data['comment']['status']) | |
|
175 | ||
|
176 | if status_color: | |
|
177 | overrides = {"color": status_color} | |
|
178 | ||
|
179 | status_text = data['comment']['status'] | |
|
180 | ||
|
181 | if data['comment']['file']: | |
|
182 | fields = [ | |
|
183 | { | |
|
184 | "title": "file", | |
|
185 | "value": data['comment']['file'] | |
|
186 | }, | |
|
187 | { | |
|
188 | "title": "line", | |
|
189 | "value": data['comment']['line'] | |
|
190 | } | |
|
191 | ] | |
|
173 | 192 | |
|
174 |
|
|
|
175 | ''' | |
|
176 | *{user}* commented on pull request <{pr_url}|#{number}> - {pr_title}: | |
|
177 | >>> {comment_status}{comment_text} | |
|
178 | ''').format( | |
|
179 | comment_status=comment_status, | |
|
180 | user=data['actor']['username'], | |
|
181 | number=data['pullrequest']['pull_request_id'], | |
|
182 | pr_url=data['pullrequest']['url'], | |
|
183 | pr_status=data['pullrequest']['status'], | |
|
184 | pr_title=data['pullrequest']['title'], | |
|
185 | comment_text=comment_text | |
|
186 | ) | |
|
193 | title = Template(textwrap.dedent(r''' | |
|
194 | *${data['actor']['username']}* left ${data['comment']['type']} on pull request <${data['pullrequest']['url']}|#${data['pullrequest']['pull_request_id']}>: | |
|
195 | ''')).render(data=data, comment=event.comment) | |
|
196 | ||
|
197 | text = Template(textwrap.dedent(r''' | |
|
198 | *pull request title*: ${pr_title} | |
|
199 | % if status_text: | |
|
200 | *submitted status*: `${status_text}` | |
|
201 | % endif | |
|
202 | >>> ${comment_text} | |
|
203 | ''')).render(comment_text=comment_text, | |
|
204 | pr_title=data['pullrequest']['title'], | |
|
205 | status_text=status_text) | |
|
206 | ||
|
207 | return title, text, fields, overrides | |
|
208 | ||
|
209 | def format_pull_request_review_event(self, event, data): | |
|
210 | title = Template(textwrap.dedent(r''' | |
|
211 | *${data['actor']['username']}* changed status of pull request <${data['pullrequest']['url']}|#${data['pullrequest']['pull_request_id']} to `${data['pullrequest']['status']}`>: | |
|
212 | ''')).render(data=data) | |
|
213 | ||
|
214 | text = Template(textwrap.dedent(r''' | |
|
215 | *pull request title*: ${pr_title} | |
|
216 | ''')).render( | |
|
217 | pr_title=data['pullrequest']['title'], | |
|
187 | 218 | ) |
|
188 | 219 | |
|
189 | def format_pull_request_review_event(self, event, data): | |
|
190 | return (textwrap.dedent( | |
|
191 | ''' | |
|
192 | Status changed to {pr_status} for pull request <{pr_url}|#{number}> - {pr_title} | |
|
193 | ''').format( | |
|
194 | user=data['actor']['username'], | |
|
195 | number=data['pullrequest']['pull_request_id'], | |
|
196 | pr_url=data['pullrequest']['url'], | |
|
197 | pr_status=data['pullrequest']['status'], | |
|
198 | pr_title=data['pullrequest']['title'], | |
|
199 | ) | |
|
200 | ) | |
|
220 | return title, text | |
|
201 | 221 | |
|
202 | 222 | def format_pull_request_event(self, event, data): |
|
203 | 223 | action = { |
@@ -207,15 +227,22 b' class SlackIntegrationType(IntegrationTy' | |||
|
207 | 227 | events.PullRequestCreateEvent: 'created', |
|
208 | 228 | }.get(event.__class__, str(event.__class__)) |
|
209 | 229 | |
|
210 | return ('Pull request <{url}|#{number}> - {title} ' | |
|
211 | '`{action}` by *{user}*').format( | |
|
212 | user=data['actor']['username'], | |
|
213 | number=data['pullrequest']['pull_request_id'], | |
|
214 | url=data['pullrequest']['url'], | |
|
215 | title=data['pullrequest']['title'], | |
|
216 | action=action | |
|
230 | title = Template(textwrap.dedent(r''' | |
|
231 | *${data['actor']['username']}* `${action}` pull request <${data['pullrequest']['url']}|#${data['pullrequest']['pull_request_id']}>: | |
|
232 | ''')).render(data=data, action=action) | |
|
233 | ||
|
234 | text = Template(textwrap.dedent(r''' | |
|
235 | *pull request title*: ${pr_title} | |
|
236 | %if data['pullrequest']['commits']: | |
|
237 | *commits*: ${len(data['pullrequest']['commits'])} | |
|
238 | %endif | |
|
239 | ''')).render( | |
|
240 | pr_title=data['pullrequest']['title'], | |
|
241 | data=data | |
|
217 | 242 | ) |
|
218 | 243 | |
|
244 | return title, text | |
|
245 | ||
|
219 | 246 | def format_repo_push_event(self, data): |
|
220 | 247 | branch_data = {branch['name']: branch |
|
221 | 248 | for branch in data['push']['branches']} |
@@ -230,20 +257,38 b' class SlackIntegrationType(IntegrationTy' | |||
|
230 | 257 | branch_commits = branches_commits[commit['branch']] |
|
231 | 258 | branch_commits['commits'].append(commit) |
|
232 | 259 | |
|
233 | result = repo_push_template.render( | |
|
260 | title = Template(r''' | |
|
261 | *${data['actor']['username']}* pushed to repo <${data['repo']['url']}|${data['repo']['repo_name']}>: | |
|
262 | ''').render(data=data) | |
|
263 | ||
|
264 | repo_push_template = Template(textwrap.dedent(r''' | |
|
265 | %for branch, branch_commits in branches_commits.items(): | |
|
266 | branch: <${branch_commits['branch']['url']}|${branch_commits['branch']['name']}> | |
|
267 | %for commit in branch_commits['commits']: | |
|
268 | `<${commit['url']}|${commit['short_id']}>` - ${commit['message_html_title']|html_to_slack_links} | |
|
269 | %endfor | |
|
270 | %endfor | |
|
271 | ''')) | |
|
272 | ||
|
273 | text = repo_push_template.render( | |
|
234 | 274 | data=data, |
|
235 | 275 | branches_commits=branches_commits, |
|
236 | 276 | html_to_slack_links=html_to_slack_links, |
|
237 | 277 | ) |
|
238 | return result | |
|
278 | ||
|
279 | return title, text | |
|
239 | 280 | |
|
240 | 281 | def format_repo_create_event(self, data): |
|
241 | return '<{}|{}> ({}) repository created by *{}*'.format( | |
|
242 | data['repo']['url'], | |
|
243 | data['repo']['repo_name'], | |
|
244 | data['repo']['repo_type'], | |
|
245 | data['actor']['username'], | |
|
246 | ) | |
|
282 | title = Template(r''' | |
|
283 | *${data['actor']['username']}* created new repository ${data['repo']['repo_name']}: | |
|
284 | ''').render(data=data) | |
|
285 | ||
|
286 | text = Template(textwrap.dedent(r''' | |
|
287 | repo_url: ${data['repo']['url']} | |
|
288 | repo_type: ${data['repo']['repo_type']} | |
|
289 | ''')).render(data=data) | |
|
290 | ||
|
291 | return title, text | |
|
247 | 292 | |
|
248 | 293 | |
|
249 | 294 | def html_to_slack_links(message): |
@@ -252,12 +297,38 b' def html_to_slack_links(message):' | |||
|
252 | 297 | |
|
253 | 298 | |
|
254 | 299 | @task(ignore_result=True) |
|
255 | def post_text_to_slack(settings, text): | |
|
256 |
log.debug('sending %s to slack %s' % ( |
|
|
257 | resp = requests.post(settings['service'], json={ | |
|
300 | def post_text_to_slack(settings, title, text, fields=None, overrides=None): | |
|
301 | log.debug('sending %s (%s) to slack %s' % ( | |
|
302 | title, text, settings['service'])) | |
|
303 | ||
|
304 | fields = fields or [] | |
|
305 | overrides = overrides or {} | |
|
306 | ||
|
307 | message_data = { | |
|
308 | "fallback": text, | |
|
309 | "color": "#427cc9", | |
|
310 | "pretext": title, | |
|
311 | #"author_name": "Bobby Tables", | |
|
312 | #"author_link": "http://flickr.com/bobby/", | |
|
313 | #"author_icon": "http://flickr.com/icons/bobby.jpg", | |
|
314 | #"title": "Slack API Documentation", | |
|
315 | #"title_link": "https://api.slack.com/", | |
|
316 | "text": text, | |
|
317 | "fields": fields, | |
|
318 | #"image_url": "http://my-website.com/path/to/image.jpg", | |
|
319 | #"thumb_url": "http://example.com/path/to/thumb.png", | |
|
320 | "footer": "RhodeCode", | |
|
321 | #"footer_icon": "", | |
|
322 | "ts": time.time(), | |
|
323 | "mrkdwn_in": ["pretext", "text"] | |
|
324 | } | |
|
325 | message_data.update(overrides) | |
|
326 | json_message = { | |
|
327 | "icon_emoji": settings.get('icon_emoji', ':studio_microphone:'), | |
|
258 | 328 | "channel": settings.get('channel', ''), |
|
259 | 329 | "username": settings.get('username', 'Rhodecode'), |
|
260 | "text": text, | |
|
261 | "icon_emoji": settings.get('icon_emoji', ':studio_microphone:') | |
|
262 | }) | |
|
330 | "attachments": [message_data] | |
|
331 | } | |
|
332 | ||
|
333 | resp = requests.post(settings['service'], json=json_message) | |
|
263 | 334 | resp.raise_for_status() # raise exception on a failed request |
General Comments 0
You need to be logged in to leave comments.
Login now