##// END OF EJS Templates
slack: updated slack integration to use the attachements for nicer formatting.
marcink -
r1467:bfe33223 default
parent child Browse files
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 process_patterns
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 matters
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 return (textwrap.dedent(
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' % (text, settings['service']))
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