##// END OF EJS Templates
integrations: sync slack/hipchat formatting
marcink -
r937:ec664d7e default
parent child Browse files
Show More
@@ -1,254 +1,254 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2012-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 from __future__ import unicode_literals
22 22 import deform
23 23 import re
24 24 import logging
25 25 import requests
26 26 import colander
27 27 import textwrap
28 28 from celery.task import task
29 29 from mako.template import Template
30 30
31 31 from rhodecode import events
32 32 from rhodecode.translation import _
33 33 from rhodecode.lib import helpers as h
34 34 from rhodecode.lib.celerylib import run_task
35 35 from rhodecode.lib.colander_utils import strip_whitespace
36 36 from rhodecode.integrations.types.base import IntegrationTypeBase
37 37
38 38 log = logging.getLogger(__name__)
39 39
40 40
41 41 class HipchatSettingsSchema(colander.Schema):
42 42 color_choices = [
43 43 ('yellow', _('Yellow')),
44 44 ('red', _('Red')),
45 45 ('green', _('Green')),
46 46 ('purple', _('Purple')),
47 47 ('gray', _('Gray')),
48 48 ]
49 49
50 50 server_url = colander.SchemaNode(
51 51 colander.String(),
52 52 title=_('Hipchat server URL'),
53 53 description=_('Hipchat integration url.'),
54 54 default='',
55 55 preparer=strip_whitespace,
56 56 validator=colander.url,
57 57 widget=deform.widget.TextInputWidget(
58 58 placeholder='https://?.hipchat.com/v2/room/?/notification?auth_token=?',
59 59 ),
60 60 )
61 61 notify = colander.SchemaNode(
62 62 colander.Bool(),
63 63 title=_('Notify'),
64 64 description=_('Make a notification to the users in room.'),
65 65 missing=False,
66 66 default=False,
67 67 )
68 68 color = colander.SchemaNode(
69 69 colander.String(),
70 70 title=_('Color'),
71 71 description=_('Background color of message.'),
72 72 missing='',
73 73 validator=colander.OneOf([x[0] for x in color_choices]),
74 74 widget=deform.widget.Select2Widget(
75 75 values=color_choices,
76 76 ),
77 77 )
78 78
79 79
80 80 repo_push_template = Template('''
81 81 <b>${data['actor']['username']}</b> pushed to repo <a href="${data['repo']['url']}">${data['repo']['repo_name']}</a>:
82 82 <br>
83 83 <ul>
84 84 %for branch, branch_commits in branches_commits.items():
85 85 <li>
86 86 <a href="${branch_commits['branch']['url']}">branch: ${branch_commits['branch']['name']}</a>
87 87 <ul>
88 88 %for commit in branch_commits['commits']:
89 89 <li><a href="${commit['url']}">${commit['short_id']}</a> - ${commit['message_html']}</li>
90 90 %endfor
91 91 </ul>
92 92 </li>
93 93 %endfor
94 94 ''')
95 95
96 96
97 97 class HipchatIntegrationType(IntegrationTypeBase):
98 98 key = 'hipchat'
99 99 display_name = _('Hipchat')
100 100 description = _('Send events such as repo pushes and pull requests to '
101 101 'your hipchat channel.')
102 102 icon = '''<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve"><g><g transform="translate(0.000000,511.000000) scale(0.100000,-0.100000)"><path fill="#205281" d="M4197.1,4662.4c-1661.5-260.4-3018-1171.6-3682.6-2473.3C219.9,1613.6,100,1120.3,100,462.6c0-1014,376.8-1918.4,1127-2699.4C2326.7-3377.6,3878.5-3898.3,5701-3730.5l486.5,44.5l208.9-123.3c637.2-373.4,1551.8-640.6,2240.4-650.9c304.9-6.9,335.7,0,417.9,75.4c185,174.7,147.3,411.1-89.1,548.1c-315.2,181.6-620,544.7-733.1,870.1l-51.4,157.6l472.7,472.7c349.4,349.4,520.7,551.5,657.7,774.2c784.5,1281.2,784.5,2788.5,0,4052.6c-236.4,376.8-794.8,966-1178.4,1236.7c-572.1,407.7-1264.1,709.1-1993.7,870.1c-267.2,58.2-479.6,75.4-1038,82.2C4714.4,4686.4,4310.2,4679.6,4197.1,4662.4z M5947.6,3740.9c1856.7-380.3,3127.6-1709.4,3127.6-3275c0-1000.3-534.4-1949.2-1466.2-2600.1c-188.4-133.6-287.8-226.1-301.5-284.4c-41.1-157.6,263.8-938.6,397.4-1020.8c20.5-10.3,34.3-44.5,34.3-75.4c0-167.8-811.9,195.3-1363.4,609.8l-181.6,137l-332.3-58.2c-445.3-78.8-1281.2-78.8-1702.6,0C2796-2569.2,1734.1-1832.6,1220.2-801.5C983.8-318.5,905,51.5,929,613.3c27.4,640.6,243.2,1192.1,685.1,1740.3c620,770.8,1661.5,1305.2,2822.8,1452.5C4806.9,3854,5553.7,3819.7,5947.6,3740.9z"/><path fill="#205281" d="M2381.5-345.9c-75.4-106.2-68.5-167.8,34.3-322c332.3-500.2,1010.6-928.4,1760.8-1120.2c417.9-106.2,1226.4-106.2,1644.3,0c712.5,181.6,1270.9,517.3,1685.4,1014C7681-561.7,7715.3-424.7,7616-325.4c-89.1,89.1-167.9,65.1-431.7-133.6c-835.8-630.3-2028-856.4-3086.5-585.8C3683.3-938.6,3142-685,2830.3-448.7C2576.8-253.4,2463.7-229.4,2381.5-345.9z"/></g></g><!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon --></svg>'''
103 103 valid_events = [
104 104 events.PullRequestCloseEvent,
105 105 events.PullRequestMergeEvent,
106 106 events.PullRequestUpdateEvent,
107 107 events.PullRequestCommentEvent,
108 108 events.PullRequestReviewEvent,
109 109 events.PullRequestCreateEvent,
110 110 events.RepoPushEvent,
111 111 events.RepoCreateEvent,
112 112 ]
113 113
114 114 def send_event(self, event):
115 115 if event.__class__ not in self.valid_events:
116 116 log.debug('event not valid: %r' % event)
117 117 return
118 118
119 119 if event.name not in self.settings['events']:
120 120 log.debug('event ignored: %r' % event)
121 121 return
122 122
123 123 data = event.as_dict()
124 124
125 125 text = '<b>%s<b> caused a <b>%s</b> event' % (
126 126 data['actor']['username'], event.name)
127 127
128 128 log.debug('handling hipchat event for %s' % event.name)
129 129
130 130 if isinstance(event, events.PullRequestCommentEvent):
131 131 text = self.format_pull_request_comment_event(event, data)
132 132 elif isinstance(event, events.PullRequestReviewEvent):
133 133 text = self.format_pull_request_review_event(event, data)
134 134 elif isinstance(event, events.PullRequestEvent):
135 135 text = self.format_pull_request_event(event, data)
136 136 elif isinstance(event, events.RepoPushEvent):
137 137 text = self.format_repo_push_event(data)
138 138 elif isinstance(event, events.RepoCreateEvent):
139 139 text = self.format_repo_create_event(data)
140 140 else:
141 141 log.error('unhandled event type: %r' % event)
142 142
143 143 run_task(post_text_to_hipchat, self.settings, text)
144 144
145 145 def settings_schema(self):
146 146 schema = HipchatSettingsSchema()
147 147 schema.add(colander.SchemaNode(
148 148 colander.Set(),
149 149 widget=deform.widget.CheckboxChoiceWidget(
150 150 values=sorted(
151 151 [(e.name, e.display_name) for e in self.valid_events]
152 152 )
153 153 ),
154 154 description="Events activated for this integration",
155 155 name='events'
156 156 ))
157 157
158 158 return schema
159 159
160 160 def format_pull_request_comment_event(self, event, data):
161 161 comment_text = data['comment']['text']
162 162 if len(comment_text) > 200:
163 163 comment_text = '{comment_text}<a href="{comment_url}">...<a/>'.format(
164 164 comment_text=h.html_escape(comment_text[:200]),
165 165 comment_url=data['comment']['url'],
166 166 )
167 167
168 168 comment_status = ''
169 169 if data['comment']['status']:
170 170 comment_status = '[{}]: '.format(data['comment']['status'])
171 171
172 172 return (textwrap.dedent(
173 173 '''
174 174 {user} commented on pull request <a href="{pr_url}">{number}</a> - {pr_title}:
175 175 >>> {comment_status}{comment_text}
176 176 ''').format(
177 177 comment_status=comment_status,
178 178 user=data['actor']['username'],
179 179 number=data['pullrequest']['pull_request_id'],
180 180 pr_url=data['pullrequest']['url'],
181 181 pr_status=data['pullrequest']['status'],
182 182 pr_title=h.html_escape(data['pullrequest']['title']),
183 183 comment_text=h.html_escape(comment_text)
184 184 )
185 185 )
186 186
187 187 def format_pull_request_review_event(self, event, data):
188 188 return (textwrap.dedent(
189 189 '''
190 190 Status changed to {pr_status} for pull request <a href="{pr_url}">#{number}</a> - {pr_title}
191 191 ''').format(
192 192 user=data['actor']['username'],
193 193 number=data['pullrequest']['pull_request_id'],
194 194 pr_url=data['pullrequest']['url'],
195 195 pr_status=data['pullrequest']['status'],
196 196 pr_title=h.html_escape(data['pullrequest']['title']),
197 197 )
198 198 )
199 199
200 200 def format_pull_request_event(self, event, data):
201 201 action = {
202 202 events.PullRequestCloseEvent: 'closed',
203 203 events.PullRequestMergeEvent: 'merged',
204 204 events.PullRequestUpdateEvent: 'updated',
205 205 events.PullRequestCreateEvent: 'created',
206 206 }.get(event.__class__, str(event.__class__))
207 207
208 208 return ('Pull request <a href="{url}">#{number}</a> - {title} '
209 '{action} by {user}').format(
209 '{action} by <b>{user}</b>').format(
210 210 user=data['actor']['username'],
211 211 number=data['pullrequest']['pull_request_id'],
212 212 url=data['pullrequest']['url'],
213 213 title=h.html_escape(data['pullrequest']['title']),
214 214 action=action
215 215 )
216 216
217 217 def format_repo_push_event(self, data):
218 218 branch_data = {branch['name']: branch
219 for branch in data['push']['branches']}
219 for branch in data['push']['branches']}
220 220
221 221 branches_commits = {}
222 222 for commit in data['push']['commits']:
223 223 if commit['branch'] not in branches_commits:
224 224 branch_commits = {'branch': branch_data[commit['branch']],
225 225 'commits': []}
226 226 branches_commits[commit['branch']] = branch_commits
227 227
228 228 branch_commits = branches_commits[commit['branch']]
229 229 branch_commits['commits'].append(commit)
230 230
231 231 result = repo_push_template.render(
232 232 data=data,
233 233 branches_commits=branches_commits,
234 234 )
235 235 return result
236 236
237 237 def format_repo_create_event(self, data):
238 238 return '<a href="{}">{}</a> ({}) repository created by <b>{}</b>'.format(
239 239 data['repo']['url'],
240 240 h.html_escape(data['repo']['repo_name']),
241 241 data['repo']['repo_type'],
242 242 data['actor']['username'],
243 243 )
244 244
245 245
246 246 @task(ignore_result=True)
247 247 def post_text_to_hipchat(settings, text):
248 248 log.debug('sending %s to hipchat %s' % (text, settings['server_url']))
249 249 resp = requests.post(settings['server_url'], json={
250 250 "message": text,
251 251 "color": settings.get('color', 'yellow'),
252 252 "notify": settings.get('notify', False),
253 253 })
254 254 resp.raise_for_status() # raise exception on a failed request
@@ -1,263 +1,263 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2012-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 from __future__ import unicode_literals
22 22 import deform
23 23 import re
24 24 import logging
25 25 import requests
26 26 import colander
27 27 import textwrap
28 28 from celery.task import task
29 29 from mako.template import Template
30 30
31 31 from rhodecode import events
32 32 from rhodecode.translation import _
33 33 from rhodecode.lib import helpers as h
34 34 from rhodecode.lib.celerylib import run_task
35 35 from rhodecode.lib.colander_utils import strip_whitespace
36 36 from rhodecode.integrations.types.base import IntegrationTypeBase
37 37
38 38 log = logging.getLogger(__name__)
39 39
40 40
41 41 class SlackSettingsSchema(colander.Schema):
42 42 service = colander.SchemaNode(
43 43 colander.String(),
44 44 title=_('Slack service URL'),
45 45 description=h.literal(_(
46 46 'This can be setup at the '
47 47 '<a href="https://my.slack.com/services/new/incoming-webhook/">'
48 48 'slack app manager</a>')),
49 49 default='',
50 50 preparer=strip_whitespace,
51 51 validator=colander.url,
52 52 widget=deform.widget.TextInputWidget(
53 53 placeholder='https://hooks.slack.com/services/...',
54 54 ),
55 55 )
56 56 username = colander.SchemaNode(
57 57 colander.String(),
58 58 title=_('Username'),
59 59 description=_('Username to show notifications coming from.'),
60 60 missing='Rhodecode',
61 61 preparer=strip_whitespace,
62 62 widget=deform.widget.TextInputWidget(
63 63 placeholder='Rhodecode'
64 64 ),
65 65 )
66 66 channel = colander.SchemaNode(
67 67 colander.String(),
68 68 title=_('Channel'),
69 69 description=_('Channel to send notifications to.'),
70 70 missing='',
71 71 preparer=strip_whitespace,
72 72 widget=deform.widget.TextInputWidget(
73 73 placeholder='#general'
74 74 ),
75 75 )
76 76 icon_emoji = colander.SchemaNode(
77 77 colander.String(),
78 78 title=_('Emoji'),
79 79 description=_('Emoji to use eg. :studio_microphone:'),
80 80 missing='',
81 81 preparer=strip_whitespace,
82 82 widget=deform.widget.TextInputWidget(
83 83 placeholder=':studio_microphone:'
84 84 ),
85 85 )
86 86
87 87
88 88 repo_push_template = Template(r'''
89 89 *${data['actor']['username']}* pushed to repo <${data['repo']['url']}|${data['repo']['repo_name']}>:
90 90 %for branch, branch_commits in branches_commits.items():
91 91 branch: <${branch_commits['branch']['url']}|${branch_commits['branch']['name']}>
92 92 %for commit in branch_commits['commits']:
93 93 > <${commit['url']}|${commit['short_id']}> - ${commit['message_html']|html_to_slack_links}
94 94 %endfor
95 95 %endfor
96 96 ''')
97 97
98 98
99 99 class SlackIntegrationType(IntegrationTypeBase):
100 100 key = 'slack'
101 101 display_name = _('Slack')
102 102 description = _('Send events such as repo pushes and pull requests to '
103 103 'your slack channel.')
104 104 icon = '''<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid"><g><path d="M165.963541,15.8384262 C162.07318,3.86308197 149.212328,-2.69009836 137.239082,1.20236066 C125.263738,5.09272131 118.710557,17.9535738 122.603016,29.9268197 L181.550164,211.292328 C185.597902,222.478689 197.682361,228.765377 209.282098,225.426885 C221.381246,221.943607 228.756984,209.093246 224.896,197.21023 C224.749115,196.756984 165.963541,15.8384262 165.963541,15.8384262" fill="#DFA22F"></path><path d="M74.6260984,45.515541 C70.7336393,33.5422951 57.8727869,26.9891148 45.899541,30.8794754 C33.9241967,34.7698361 27.3710164,47.6306885 31.2634754,59.6060328 L90.210623,240.971541 C94.2583607,252.157902 106.34282,258.44459 117.942557,255.104 C130.041705,251.62282 137.417443,238.772459 133.556459,226.887344 C133.409574,226.436197 74.6260984,45.515541 74.6260984,45.515541" fill="#3CB187"></path><path d="M240.161574,166.045377 C252.136918,162.155016 258.688,149.294164 254.797639,137.31882 C250.907279,125.345574 238.046426,118.792393 226.07318,122.682754 L44.7076721,181.632 C33.5213115,185.677639 27.234623,197.762098 30.5731148,209.361836 C34.0563934,221.460984 46.9067541,228.836721 58.7897705,224.975738 C59.2430164,224.828852 240.161574,166.045377 240.161574,166.045377" fill="#CE1E5B"></path><path d="M82.507541,217.270557 C94.312918,213.434754 109.528131,208.491016 125.855475,203.186361 C122.019672,191.380984 117.075934,176.163672 111.76918,159.83423 L68.4191475,173.924721 L82.507541,217.270557" fill="#392538"></path><path d="M173.847082,187.591344 C190.235279,182.267803 205.467279,177.31777 217.195016,173.507148 C213.359213,161.70177 208.413377,146.480262 203.106623,130.146623 L159.75659,144.237115 L173.847082,187.591344" fill="#BB242A"></path><path d="M210.484459,74.7058361 C222.457705,70.8154754 229.010885,57.954623 225.120525,45.9792787 C221.230164,34.0060328 208.369311,27.4528525 196.393967,31.3432131 L15.028459,90.292459 C3.84209836,94.3380984 -2.44459016,106.422557 0.896,118.022295 C4.37718033,130.121443 17.227541,137.49718 29.1126557,133.636197 C29.5638033,133.489311 210.484459,74.7058361 210.484459,74.7058361" fill="#72C5CD"></path><path d="M52.8220328,125.933115 C64.6274098,122.097311 79.8468197,117.151475 96.1762623,111.84682 C90.8527213,95.4565246 85.9026885,80.2245246 82.0920656,68.4946885 L38.731541,82.5872787 L52.8220328,125.933115" fill="#248C73"></path><path d="M144.159475,96.256 C160.551869,90.9303607 175.785967,85.9803279 187.515803,82.1676066 C182.190164,65.7752131 177.240131,50.5390164 173.42741,38.807082 L130.068984,52.8996721 L144.159475,96.256" fill="#62803A"></path></g></svg>'''
105 105 valid_events = [
106 106 events.PullRequestCloseEvent,
107 107 events.PullRequestMergeEvent,
108 108 events.PullRequestUpdateEvent,
109 109 events.PullRequestCommentEvent,
110 110 events.PullRequestReviewEvent,
111 111 events.PullRequestCreateEvent,
112 112 events.RepoPushEvent,
113 113 events.RepoCreateEvent,
114 114 ]
115 115
116 116 def send_event(self, event):
117 117 if event.__class__ not in self.valid_events:
118 118 log.debug('event not valid: %r' % event)
119 119 return
120 120
121 121 if event.name not in self.settings['events']:
122 122 log.debug('event ignored: %r' % event)
123 123 return
124 124
125 125 data = event.as_dict()
126 126
127 127 text = '*%s* caused a *%s* event' % (
128 128 data['actor']['username'], event.name)
129 129
130 130 log.debug('handling slack event for %s' % event.name)
131 131
132 132 if isinstance(event, events.PullRequestCommentEvent):
133 133 text = self.format_pull_request_comment_event(event, data)
134 134 elif isinstance(event, events.PullRequestReviewEvent):
135 135 text = self.format_pull_request_review_event(event, data)
136 136 elif isinstance(event, events.PullRequestEvent):
137 137 text = self.format_pull_request_event(event, data)
138 138 elif isinstance(event, events.RepoPushEvent):
139 139 text = self.format_repo_push_event(data)
140 140 elif isinstance(event, events.RepoCreateEvent):
141 141 text = self.format_repo_create_event(data)
142 142 else:
143 143 log.error('unhandled event type: %r' % event)
144 144
145 145 run_task(post_text_to_slack, self.settings, text)
146 146
147 147 def settings_schema(self):
148 148 schema = SlackSettingsSchema()
149 149 schema.add(colander.SchemaNode(
150 150 colander.Set(),
151 151 widget=deform.widget.CheckboxChoiceWidget(
152 152 values=sorted(
153 153 [(e.name, e.display_name) for e in self.valid_events]
154 154 )
155 155 ),
156 156 description="Events activated for this integration",
157 157 name='events'
158 158 ))
159 159
160 160 return schema
161 161
162 162 def format_pull_request_comment_event(self, event, data):
163 163 comment_text = data['comment']['text']
164 164 if len(comment_text) > 200:
165 165 comment_text = '<{comment_url}|{comment_text}...>'.format(
166 166 comment_text=comment_text[:200],
167 167 comment_url=data['comment']['url'],
168 168 )
169 169
170 170 comment_status = ''
171 171 if data['comment']['status']:
172 172 comment_status = '[{}]: '.format(data['comment']['status'])
173 173
174 174 return (textwrap.dedent(
175 175 '''
176 176 *{user}* commented on pull request <{pr_url}|#{number}> - {pr_title}:
177 177 >>> {comment_status}{comment_text}
178 178 ''').format(
179 179 comment_status=comment_status,
180 180 user=data['actor']['username'],
181 181 number=data['pullrequest']['pull_request_id'],
182 182 pr_url=data['pullrequest']['url'],
183 183 pr_status=data['pullrequest']['status'],
184 184 pr_title=data['pullrequest']['title'],
185 185 comment_text=comment_text
186 186 )
187 187 )
188 188
189 189 def format_pull_request_review_event(self, event, data):
190 190 return (textwrap.dedent(
191 191 '''
192 192 Status changed to {pr_status} for pull request <{pr_url}|#{number}> - {pr_title}
193 193 ''').format(
194 194 user=data['actor']['username'],
195 195 number=data['pullrequest']['pull_request_id'],
196 196 pr_url=data['pullrequest']['url'],
197 197 pr_status=data['pullrequest']['status'],
198 198 pr_title=data['pullrequest']['title'],
199 199 )
200 200 )
201 201
202 202 def format_pull_request_event(self, event, data):
203 203 action = {
204 204 events.PullRequestCloseEvent: 'closed',
205 205 events.PullRequestMergeEvent: 'merged',
206 206 events.PullRequestUpdateEvent: 'updated',
207 207 events.PullRequestCreateEvent: 'created',
208 208 }.get(event.__class__, str(event.__class__))
209 209
210 210 return ('Pull request <{url}|#{number}> - {title} '
211 211 '`{action}` by *{user}*').format(
212 212 user=data['actor']['username'],
213 213 number=data['pullrequest']['pull_request_id'],
214 214 url=data['pullrequest']['url'],
215 215 title=data['pullrequest']['title'],
216 216 action=action
217 217 )
218 218
219 219 def format_repo_push_event(self, data):
220 220 branch_data = {branch['name']: branch
221 for branch in data['push']['branches']}
221 for branch in data['push']['branches']}
222 222
223 223 branches_commits = {}
224 224 for commit in data['push']['commits']:
225 225 if commit['branch'] not in branches_commits:
226 226 branch_commits = {'branch': branch_data[commit['branch']],
227 227 'commits': []}
228 228 branches_commits[commit['branch']] = branch_commits
229 229
230 230 branch_commits = branches_commits[commit['branch']]
231 231 branch_commits['commits'].append(commit)
232 232
233 233 result = repo_push_template.render(
234 234 data=data,
235 235 branches_commits=branches_commits,
236 236 html_to_slack_links=html_to_slack_links,
237 237 )
238 238 return result
239 239
240 240 def format_repo_create_event(self, data):
241 241 return '<{}|{}> ({}) repository created by *{}*'.format(
242 242 data['repo']['url'],
243 243 data['repo']['repo_name'],
244 244 data['repo']['repo_type'],
245 245 data['actor']['username'],
246 246 )
247 247
248 248
249 249 def html_to_slack_links(message):
250 250 return re.compile(r'<a .*?href=["\'](.+?)".*?>(.+?)</a>').sub(
251 251 r'<\1|\2>', message)
252 252
253 253
254 254 @task(ignore_result=True)
255 255 def post_text_to_slack(settings, text):
256 256 log.debug('sending %s to slack %s' % (text, settings['service']))
257 257 resp = requests.post(settings['service'], json={
258 258 "channel": settings.get('channel', ''),
259 259 "username": settings.get('username', 'Rhodecode'),
260 260 "text": text,
261 261 "icon_emoji": settings.get('icon_emoji', ':studio_microphone:')
262 262 })
263 263 resp.raise_for_status() # raise exception on a failed request
General Comments 0
You need to be logged in to leave comments. Login now