Add support for the Hipchat room notification API
This commit is contained in:
parent
35bd28a77e
commit
32ea1d194f
7 changed files with 156 additions and 3 deletions
|
@ -15,6 +15,13 @@ class NotificationEvent(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def get_level(self, event_data, notification_data):
|
||||||
|
"""
|
||||||
|
Returns a 'level' representing the severity of the event.
|
||||||
|
Valid values are: 'info', 'warning', 'error', 'primary'
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
def get_summary(self, event_data, notification_data):
|
def get_summary(self, event_data, notification_data):
|
||||||
"""
|
"""
|
||||||
Returns a human readable one-line summary for the given notification data.
|
Returns a human readable one-line summary for the given notification data.
|
||||||
|
@ -55,6 +62,9 @@ class RepoPushEvent(NotificationEvent):
|
||||||
def event_name(cls):
|
def event_name(cls):
|
||||||
return 'repo_push'
|
return 'repo_push'
|
||||||
|
|
||||||
|
def get_level(self, event_data, notification_data):
|
||||||
|
return 'info'
|
||||||
|
|
||||||
def get_summary(self, event_data, notification_data):
|
def get_summary(self, event_data, notification_data):
|
||||||
return 'Repository %s updated' % (event_data['repository'])
|
return 'Repository %s updated' % (event_data['repository'])
|
||||||
|
|
||||||
|
@ -87,6 +97,9 @@ class BuildQueueEvent(NotificationEvent):
|
||||||
@classmethod
|
@classmethod
|
||||||
def event_name(cls):
|
def event_name(cls):
|
||||||
return 'build_queued'
|
return 'build_queued'
|
||||||
|
|
||||||
|
def get_level(self, event_data, notification_data):
|
||||||
|
return 'info'
|
||||||
|
|
||||||
def get_sample_data(self, repository):
|
def get_sample_data(self, repository):
|
||||||
build_uuid = 'fake-build-id'
|
build_uuid = 'fake-build-id'
|
||||||
|
@ -127,6 +140,9 @@ class BuildStartEvent(NotificationEvent):
|
||||||
def event_name(cls):
|
def event_name(cls):
|
||||||
return 'build_start'
|
return 'build_start'
|
||||||
|
|
||||||
|
def get_level(self, event_data, notification_data):
|
||||||
|
return 'info'
|
||||||
|
|
||||||
def get_sample_data(self, repository):
|
def get_sample_data(self, repository):
|
||||||
build_uuid = 'fake-build-id'
|
build_uuid = 'fake-build-id'
|
||||||
|
|
||||||
|
@ -155,6 +171,9 @@ class BuildSuccessEvent(NotificationEvent):
|
||||||
def event_name(cls):
|
def event_name(cls):
|
||||||
return 'build_success'
|
return 'build_success'
|
||||||
|
|
||||||
|
def get_level(self, event_data, notification_data):
|
||||||
|
return 'primary'
|
||||||
|
|
||||||
def get_sample_data(self, repository):
|
def get_sample_data(self, repository):
|
||||||
build_uuid = 'fake-build-id'
|
build_uuid = 'fake-build-id'
|
||||||
|
|
||||||
|
@ -183,6 +202,9 @@ class BuildFailureEvent(NotificationEvent):
|
||||||
def event_name(cls):
|
def event_name(cls):
|
||||||
return 'build_failure'
|
return 'build_failure'
|
||||||
|
|
||||||
|
def get_level(self, event_data, notification_data):
|
||||||
|
return 'error'
|
||||||
|
|
||||||
def get_sample_data(self, repository):
|
def get_sample_data(self, repository):
|
||||||
build_uuid = 'fake-build-id'
|
build_uuid = 'fake-build-id'
|
||||||
|
|
||||||
|
|
|
@ -240,3 +240,65 @@ class FlowdockMethod(NotificationMethod):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class HipchatMethod(NotificationMethod):
|
||||||
|
""" Method for sending notifications to Hipchat via the API:
|
||||||
|
https://www.hipchat.com/docs/apiv2/method/send_room_notification
|
||||||
|
"""
|
||||||
|
@classmethod
|
||||||
|
def method_name(cls):
|
||||||
|
return 'hipchat'
|
||||||
|
|
||||||
|
def validate(self, repository, config_data):
|
||||||
|
if not config_data.get('notification_token', ''):
|
||||||
|
raise CannotValidateNotificationMethodException('Missing Hipchat Room Notification Token')
|
||||||
|
|
||||||
|
if not config_data.get('room_id', ''):
|
||||||
|
raise CannotValidateNotificationMethodException('Missing Hipchat Room ID')
|
||||||
|
|
||||||
|
def perform(self, notification, event_handler, notification_data):
|
||||||
|
config_data = json.loads(notification.config_json)
|
||||||
|
|
||||||
|
token = config_data.get('notification_token', '')
|
||||||
|
room_id = config_data.get('room_id', '')
|
||||||
|
|
||||||
|
if not token or not room_id:
|
||||||
|
return False
|
||||||
|
|
||||||
|
owner = model.get_user(notification.repository.namespace)
|
||||||
|
if not owner:
|
||||||
|
# Something went wrong.
|
||||||
|
return False
|
||||||
|
|
||||||
|
url = 'https://api.hipchat.com/v2/room/%s/notification?auth_token=%s' % (room_id, token)
|
||||||
|
|
||||||
|
level = event_handler.get_level(notification_data['event_data'], notification_data)
|
||||||
|
color = {
|
||||||
|
'info': 'gray',
|
||||||
|
'warning': 'yellow',
|
||||||
|
'error': 'red',
|
||||||
|
'primary': 'purple'
|
||||||
|
}.get(level, 'gray')
|
||||||
|
|
||||||
|
headers = {'Content-type': 'application/json'}
|
||||||
|
payload = {
|
||||||
|
'color': color,
|
||||||
|
'message': event_handler.get_message(notification_data['event_data'], notification_data),
|
||||||
|
'notify': level == 'error',
|
||||||
|
'message_format': 'html',
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
resp = requests.post(url, data=json.dumps(payload), headers=headers)
|
||||||
|
if resp.status_code/100 != 2:
|
||||||
|
logger.error('%s response for hipchat to url: %s' % (resp.status_code,
|
||||||
|
url))
|
||||||
|
logger.error(resp.content)
|
||||||
|
return False
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as ex:
|
||||||
|
logger.exception('Hipchat method was unable to be sent: %s' % ex.message)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
|
@ -252,6 +252,7 @@ def initialize_database():
|
||||||
ExternalNotificationMethod.create(name='webhook')
|
ExternalNotificationMethod.create(name='webhook')
|
||||||
|
|
||||||
ExternalNotificationMethod.create(name='flowdock')
|
ExternalNotificationMethod.create(name='flowdock')
|
||||||
|
ExternalNotificationMethod.create(name='hipchat')
|
||||||
|
|
||||||
NotificationKind.create(name='repo_push')
|
NotificationKind.create(name='repo_push')
|
||||||
NotificationKind.create(name='build_queued')
|
NotificationKind.create(name='build_queued')
|
||||||
|
|
|
@ -4566,6 +4566,13 @@ i.flowdock-icon {
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i.hipchat-icon {
|
||||||
|
background-image: url(/static/img/hipchat.png);
|
||||||
|
background-size: 16px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.external-notification-view-element {
|
.external-notification-view-element {
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
|
|
|
@ -88,8 +88,8 @@
|
||||||
allowed-entities="['user', 'team', 'org']"
|
allowed-entities="['user', 'team', 'org']"
|
||||||
ng-switch-when="entity"></div>
|
ng-switch-when="entity"></div>
|
||||||
|
|
||||||
<div ng-if="field.help_url" style="margin-top: 10px">
|
<div ng-if="getHelpUrl(field, currentConfig)" style="margin-top: 10px">
|
||||||
See: <a href="{{ field.help_url }}" target="_blank">{{ field.help_url }}</a>
|
See: <a href="{{ getHelpUrl(field, currentConfig) }}" target="_blank">{{ getHelpUrl(field, currentConfig) }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
BIN
static/img/hipchat.png
Normal file
BIN
static/img/hipchat.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
|
@ -513,6 +513,41 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
||||||
$provide.factory('StringBuilderService', ['$sce', 'UtilService', function($sce, UtilService) {
|
$provide.factory('StringBuilderService', ['$sce', 'UtilService', function($sce, UtilService) {
|
||||||
var stringBuilderService = {};
|
var stringBuilderService = {};
|
||||||
|
|
||||||
|
stringBuilderService.buildUrl = function(value_or_func, metadata) {
|
||||||
|
var url = value_or_func;
|
||||||
|
if (typeof url != 'string') {
|
||||||
|
url = url(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the variables to be replaced.
|
||||||
|
var varNames = [];
|
||||||
|
for (var i = 0; i < url.length; ++i) {
|
||||||
|
var c = url[i];
|
||||||
|
if (c == '{') {
|
||||||
|
for (var j = i + 1; j < url.length; ++j) {
|
||||||
|
var d = url[j];
|
||||||
|
if (d == '}') {
|
||||||
|
varNames.push(url.substring(i + 1, j));
|
||||||
|
i = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace all variables found.
|
||||||
|
for (var i = 0; i < varNames.length; ++i) {
|
||||||
|
var varName = varNames[i];
|
||||||
|
if (!metadata[varName]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
url = url.replace('{' + varName + '}', metadata[varName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
};
|
||||||
|
|
||||||
stringBuilderService.buildString = function(value_or_func, metadata) {
|
stringBuilderService.buildString = function(value_or_func, metadata) {
|
||||||
var fieldIcons = {
|
var fieldIcons = {
|
||||||
'username': 'user',
|
'username': 'user',
|
||||||
|
@ -1089,6 +1124,23 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
||||||
'help_url': 'https://www.flowdock.com/account/tokens'
|
'help_url': 'https://www.flowdock.com/account/tokens'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'hipchat',
|
||||||
|
'title': 'HipChat Room Notification',
|
||||||
|
'icon': 'hipchat-icon',
|
||||||
|
'fields': [
|
||||||
|
{
|
||||||
|
'name': 'room_id',
|
||||||
|
'type': 'string',
|
||||||
|
'title': 'Room ID #'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'notification_token',
|
||||||
|
'type': 'string',
|
||||||
|
'title': 'Notification Token'
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -4830,7 +4882,7 @@ quayApp.directive('createExternalNotificationDialog', function () {
|
||||||
'counter': '=counter',
|
'counter': '=counter',
|
||||||
'notificationCreated': '¬ificationCreated'
|
'notificationCreated': '¬ificationCreated'
|
||||||
},
|
},
|
||||||
controller: function($scope, $element, ExternalNotificationData, ApiService, $timeout) {
|
controller: function($scope, $element, ExternalNotificationData, ApiService, $timeout, StringBuilderService) {
|
||||||
$scope.currentEvent = null;
|
$scope.currentEvent = null;
|
||||||
$scope.currentMethod = null;
|
$scope.currentMethod = null;
|
||||||
$scope.status = '';
|
$scope.status = '';
|
||||||
|
@ -4930,6 +4982,15 @@ quayApp.directive('createExternalNotificationDialog', function () {
|
||||||
}, 1000);
|
}, 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.getHelpUrl = function(field, config) {
|
||||||
|
var helpUrl = field['help_url'];
|
||||||
|
if (!helpUrl) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return StringBuilderService.buildUrl(helpUrl, config);
|
||||||
|
};
|
||||||
|
|
||||||
$scope.$watch('counter', function(counter) {
|
$scope.$watch('counter', function(counter) {
|
||||||
if (counter) {
|
if (counter) {
|
||||||
$scope.clearCounter++;
|
$scope.clearCounter++;
|
||||||
|
|
Reference in a new issue