##// END OF EJS Templates
integrations: show branches/commits separately when posting push...
dan -
r776:f73a9bfb default
parent child Browse files
Show More
@@ -1,243 +1,255 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 <b>${data['actor']['username']}</b> pushed to
82 %if data['push']['branches']:
83 ${len(data['push']['branches']) > 1 and 'branches' or 'branch'}
84 ${', '.join('<a href="%s">%s</a>' % (branch['url'], branch['name']) for branch in data['push']['branches'])}
85 %else:
86 unknown branch
87 %endif
88 in <a href="${data['repo']['url']}">${data['repo']['repo_name']}</a>
81 <b>${data['actor']['username']}</b> pushed to repo <a href="${data['repo']['url']}">${data['repo']['repo_name']}</a>:
89 82 <br>
90 83 <ul>
91 %for commit in data['push']['commits']:
84 %for branch, branch_commits in branches_commits.items():
92 85 <li>
93 <a href="${commit['url']}">${commit['short_id']}</a> - ${commit['message_html']}
86 <a href="${branch_commits['branch']['url']}">branch: ${branch_commits['branch']['name']}</a>
87 <ul>
88 %for commit in branch_commits['commits']:
89 <li><a href="${commit['url']}">${commit['short_id']}</a> - ${commit['message_html']}</li>
90 %endfor
91 </ul>
94 92 </li>
95 93 %endfor
96 </ul>
97 94 ''')
98 95
99 96
100 97 class HipchatIntegrationType(IntegrationTypeBase):
101 98 key = 'hipchat'
102 99 display_name = _('Hipchat')
103 100 description = _('Send events such as repo pushes and pull requests to '
104 101 'your hipchat channel.')
105 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>'''
106 103 valid_events = [
107 104 events.PullRequestCloseEvent,
108 105 events.PullRequestMergeEvent,
109 106 events.PullRequestUpdateEvent,
110 107 events.PullRequestCommentEvent,
111 108 events.PullRequestReviewEvent,
112 109 events.PullRequestCreateEvent,
113 110 events.RepoPushEvent,
114 111 events.RepoCreateEvent,
115 112 ]
116 113
117 114 def send_event(self, event):
118 115 if event.__class__ not in self.valid_events:
119 116 log.debug('event not valid: %r' % event)
120 117 return
121 118
122 119 if event.name not in self.settings['events']:
123 120 log.debug('event ignored: %r' % event)
124 121 return
125 122
126 123 data = event.as_dict()
127 124
128 125 text = '<b>%s<b> caused a <b>%s</b> event' % (
129 126 data['actor']['username'], event.name)
130 127
131 128 log.debug('handling hipchat event for %s' % event.name)
132 129
133 130 if isinstance(event, events.PullRequestCommentEvent):
134 131 text = self.format_pull_request_comment_event(event, data)
135 132 elif isinstance(event, events.PullRequestReviewEvent):
136 133 text = self.format_pull_request_review_event(event, data)
137 134 elif isinstance(event, events.PullRequestEvent):
138 135 text = self.format_pull_request_event(event, data)
139 136 elif isinstance(event, events.RepoPushEvent):
140 137 text = self.format_repo_push_event(data)
141 138 elif isinstance(event, events.RepoCreateEvent):
142 139 text = self.format_repo_create_event(data)
143 140 else:
144 141 log.error('unhandled event type: %r' % event)
145 142
146 143 run_task(post_text_to_hipchat, self.settings, text)
147 144
148 145 def settings_schema(self):
149 146 schema = HipchatSettingsSchema()
150 147 schema.add(colander.SchemaNode(
151 148 colander.Set(),
152 149 widget=deform.widget.CheckboxChoiceWidget(
153 150 values=sorted(
154 151 [(e.name, e.display_name) for e in self.valid_events]
155 152 )
156 153 ),
157 154 description="Events activated for this integration",
158 155 name='events'
159 156 ))
160 157
161 158 return schema
162 159
163 160 def format_pull_request_comment_event(self, event, data):
164 161 comment_text = data['comment']['text']
165 162 if len(comment_text) > 200:
166 163 comment_text = '{comment_text}<a href="{comment_url}">...<a/>'.format(
167 164 comment_text=comment_text[:200],
168 165 comment_url=data['comment']['url'],
169 166 )
170 167
171 168 comment_status = ''
172 169 if data['comment']['status']:
173 170 comment_status = '[{}]: '.format(data['comment']['status'])
174 171
175 172 return (textwrap.dedent(
176 173 '''
177 174 {user} commented on pull request <a href="{pr_url}">{number}</a> - {pr_title}:
178 175 >>> {comment_status}{comment_text}
179 176 ''').format(
180 177 comment_status=comment_status,
181 178 user=data['actor']['username'],
182 179 number=data['pullrequest']['pull_request_id'],
183 180 pr_url=data['pullrequest']['url'],
184 181 pr_status=data['pullrequest']['status'],
185 182 pr_title=data['pullrequest']['title'],
186 183 comment_text=comment_text
187 184 )
188 185 )
189 186
190 187 def format_pull_request_review_event(self, event, data):
191 188 return (textwrap.dedent(
192 189 '''
193 190 Status changed to {pr_status} for pull request <a href="{pr_url}">#{number}</a> - {pr_title}
194 191 ''').format(
195 192 user=data['actor']['username'],
196 193 number=data['pullrequest']['pull_request_id'],
197 194 pr_url=data['pullrequest']['url'],
198 195 pr_status=data['pullrequest']['status'],
199 196 pr_title=data['pullrequest']['title'],
200 197 )
201 198 )
202 199
203 200 def format_pull_request_event(self, event, data):
204 201 action = {
205 202 events.PullRequestCloseEvent: 'closed',
206 203 events.PullRequestMergeEvent: 'merged',
207 204 events.PullRequestUpdateEvent: 'updated',
208 205 events.PullRequestCreateEvent: 'created',
209 206 }.get(event.__class__, str(event.__class__))
210 207
211 208 return ('Pull request <a href="{url}">#{number}</a> - {title} '
212 209 '{action} by {user}').format(
213 210 user=data['actor']['username'],
214 211 number=data['pullrequest']['pull_request_id'],
215 212 url=data['pullrequest']['url'],
216 213 title=data['pullrequest']['title'],
217 214 action=action
218 215 )
219 216
220 217 def format_repo_push_event(self, data):
218 branch_data = {branch['name']: branch
219 for branch in data['push']['branches']}
220
221 branches_commits = {}
222 for commit in data['push']['commits']:
223 log.critical(commit)
224 if commit['branch'] not in branches_commits:
225 branch_commits = {'branch': branch_data[commit['branch']],
226 'commits': []}
227 branches_commits[commit['branch']] = branch_commits
228
229 branch_commits = branches_commits[commit['branch']]
230 branch_commits['commits'].append(commit)
231
221 232 result = repo_push_template.render(
222 233 data=data,
234 branches_commits=branches_commits,
223 235 )
224 236 return result
225 237
226 238 def format_repo_create_event(self, data):
227 239 return '<a href="{}">{}</a> ({}) repository created by <b>{}</b>'.format(
228 240 data['repo']['url'],
229 241 data['repo']['repo_name'],
230 242 data['repo']['repo_type'],
231 243 data['actor']['username'],
232 244 )
233 245
234 246
235 247 @task(ignore_result=True)
236 248 def post_text_to_hipchat(settings, text):
237 249 log.debug('sending %s to hipchat %s' % (text, settings['server_url']))
238 250 resp = requests.post(settings['server_url'], json={
239 251 "message": text,
240 252 "color": settings.get('color', 'yellow'),
241 253 "notify": settings.get('notify', False),
242 254 })
243 255 resp.raise_for_status() # raise exception on a failed request
@@ -1,256 +1,264 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 *${data['actor']['username']}* pushed to \
90 %if data['push']['branches']:
91 ${len(data['push']['branches']) > 1 and 'branches' or 'branch'} \
92 ${', '.join('<%s|%s>' % (branch['url'], branch['name']) for branch in data['push']['branches'])} \
93 %else:
94 unknown branch \
95 %endif
96 in <${data['repo']['url']}|${data['repo']['repo_name']}>
97 >>>
98 %for commit in data['push']['commits']:
99 <${commit['url']}|${commit['short_id']}> - ${commit['message_html']|html_to_slack_links}
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
100 95 %endfor
101 96 ''')
102 97
103 98
104
105
106 99 class SlackIntegrationType(IntegrationTypeBase):
107 100 key = 'slack'
108 101 display_name = _('Slack')
109 102 description = _('Send events such as repo pushes and pull requests to '
110 103 'your slack channel.')
111 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>'''
112 105 valid_events = [
113 106 events.PullRequestCloseEvent,
114 107 events.PullRequestMergeEvent,
115 108 events.PullRequestUpdateEvent,
116 109 events.PullRequestCommentEvent,
117 110 events.PullRequestReviewEvent,
118 111 events.PullRequestCreateEvent,
119 112 events.RepoPushEvent,
120 113 events.RepoCreateEvent,
121 114 ]
122 115
123 116 def send_event(self, event):
124 117 if event.__class__ not in self.valid_events:
125 118 log.debug('event not valid: %r' % event)
126 119 return
127 120
128 121 if event.name not in self.settings['events']:
129 122 log.debug('event ignored: %r' % event)
130 123 return
131 124
132 125 data = event.as_dict()
133 126
134 127 text = '*%s* caused a *%s* event' % (
135 128 data['actor']['username'], event.name)
136 129
137 130 log.debug('handling slack event for %s' % event.name)
138 131
139 132 if isinstance(event, events.PullRequestCommentEvent):
140 133 text = self.format_pull_request_comment_event(event, data)
141 134 elif isinstance(event, events.PullRequestReviewEvent):
142 135 text = self.format_pull_request_review_event(event, data)
143 136 elif isinstance(event, events.PullRequestEvent):
144 137 text = self.format_pull_request_event(event, data)
145 138 elif isinstance(event, events.RepoPushEvent):
146 139 text = self.format_repo_push_event(data)
147 140 elif isinstance(event, events.RepoCreateEvent):
148 141 text = self.format_repo_create_event(data)
149 142 else:
150 143 log.error('unhandled event type: %r' % event)
151 144
152 145 run_task(post_text_to_slack, self.settings, text)
153 146
154 147 def settings_schema(self):
155 148 schema = SlackSettingsSchema()
156 149 schema.add(colander.SchemaNode(
157 150 colander.Set(),
158 151 widget=deform.widget.CheckboxChoiceWidget(
159 152 values=sorted(
160 153 [(e.name, e.display_name) for e in self.valid_events]
161 154 )
162 155 ),
163 156 description="Events activated for this integration",
164 157 name='events'
165 158 ))
166 159
167 160 return schema
168 161
169 162 def format_pull_request_comment_event(self, event, data):
170 163 comment_text = data['comment']['text']
171 164 if len(comment_text) > 200:
172 165 comment_text = '<{comment_url}|{comment_text}...>'.format(
173 166 comment_text=comment_text[:200],
174 167 comment_url=data['comment']['url'],
175 168 )
176 169
177 170 comment_status = ''
178 171 if data['comment']['status']:
179 172 comment_status = '[{}]: '.format(data['comment']['status'])
180 173
181 174 return (textwrap.dedent(
182 175 '''
183 176 {user} commented on pull request <{pr_url}|#{number}> - {pr_title}:
184 177 >>> {comment_status}{comment_text}
185 178 ''').format(
186 179 comment_status=comment_status,
187 180 user=data['actor']['username'],
188 181 number=data['pullrequest']['pull_request_id'],
189 182 pr_url=data['pullrequest']['url'],
190 183 pr_status=data['pullrequest']['status'],
191 184 pr_title=data['pullrequest']['title'],
192 185 comment_text=comment_text
193 186 )
194 187 )
195 188
196 189 def format_pull_request_review_event(self, event, data):
197 190 return (textwrap.dedent(
198 191 '''
199 192 Status changed to {pr_status} for pull request <{pr_url}|#{number}> - {pr_title}
200 193 ''').format(
201 194 user=data['actor']['username'],
202 195 number=data['pullrequest']['pull_request_id'],
203 196 pr_url=data['pullrequest']['url'],
204 197 pr_status=data['pullrequest']['status'],
205 198 pr_title=data['pullrequest']['title'],
206 199 )
207 200 )
208 201
209 202 def format_pull_request_event(self, event, data):
210 203 action = {
211 204 events.PullRequestCloseEvent: 'closed',
212 205 events.PullRequestMergeEvent: 'merged',
213 206 events.PullRequestUpdateEvent: 'updated',
214 207 events.PullRequestCreateEvent: 'created',
215 208 }.get(event.__class__, str(event.__class__))
216 209
217 210 return ('Pull request <{url}|#{number}> - {title} '
218 211 '{action} by {user}').format(
219 212 user=data['actor']['username'],
220 213 number=data['pullrequest']['pull_request_id'],
221 214 url=data['pullrequest']['url'],
222 215 title=data['pullrequest']['title'],
223 216 action=action
224 217 )
225 218
226 219 def format_repo_push_event(self, data):
220 branch_data = {branch['name']: branch
221 for branch in data['push']['branches']}
222
223 branches_commits = {}
224 for commit in data['push']['commits']:
225 log.critical(commit)
226 if commit['branch'] not in branches_commits:
227 branch_commits = {'branch': branch_data[commit['branch']],
228 'commits': []}
229 branches_commits[commit['branch']] = branch_commits
230
231 branch_commits = branches_commits[commit['branch']]
232 branch_commits['commits'].append(commit)
233
227 234 result = repo_push_template.render(
228 235 data=data,
236 branches_commits=branches_commits,
229 237 html_to_slack_links=html_to_slack_links,
230 238 )
231 239 return result
232 240
233 241 def format_repo_create_event(self, data):
234 242 return '<{}|{}> ({}) repository created by *{}*'.format(
235 243 data['repo']['url'],
236 244 data['repo']['repo_name'],
237 245 data['repo']['repo_type'],
238 246 data['actor']['username'],
239 247 )
240 248
241 249
242 250 def html_to_slack_links(message):
243 251 return re.compile(r'<a .*?href=["\'](.+?)".*?>(.+?)</a>').sub(
244 252 r'<\1|\2>', message)
245 253
246 254
247 255 @task(ignore_result=True)
248 256 def post_text_to_slack(settings, text):
249 257 log.debug('sending %s to slack %s' % (text, settings['service']))
250 258 resp = requests.post(settings['service'], json={
251 259 "channel": settings.get('channel', ''),
252 260 "username": settings.get('username', 'Rhodecode'),
253 261 "text": text,
254 262 "icon_emoji": settings.get('icon_emoji', ':studio_microphone:')
255 263 })
256 264 resp.raise_for_status() # raise exception on a failed request
General Comments 0
You need to be logged in to leave comments. Login now