BuildNotify-0.3.5/ 0000755 0001750 0001750 00000000000 12315063430 013646 5 ustar anay anay 0000000 0000000 BuildNotify-0.3.5/buildnotifyapplet.py 0000755 0001750 0001750 00000000112 12315063423 017755 0 ustar anay anay 0000000 0000000 #!/usr/bin/env python
import buildnotifylib
buildnotifylib.BuildNotify()
BuildNotify-0.3.5/setup.py 0000644 0001750 0001750 00000001551 12315063423 015364 0 ustar anay anay 0000000 0000000 #!/usr/bin/env python
from setuptools import setup
setup (name='BuildNotify',
version="0.3.5",
description='Cruise Control build monitor for Windows/Linux/Mac',
keywords='cctray ccmenu buildnotify ubuntu linux cruisecontrol continuous integration ci',
author='Anay Nayak',
requires = ['pytz'],
author_email='anayak007@gmail.com',
url = "http://bitbucket.org/Anay/buildnotify/",
license='GPL v3',
long_description = 'BuildNotify is a cruise control system tray monitor which works on Windows/Linux/Mac.' +
'It was largely inspired from CCMenu and lets you monitor multiple continuous integration servers with' +
'customizable build notifications for all projects',
packages=['buildnotifylib', 'buildnotifylib.core', 'buildnotifylib.generated'],
scripts = ['buildnotifyapplet.py'])
BuildNotify-0.3.5/BuildNotify.egg-info/ 0000755 0001750 0001750 00000000000 12315063430 017570 5 ustar anay anay 0000000 0000000 BuildNotify-0.3.5/BuildNotify.egg-info/top_level.txt 0000664 0001750 0001750 00000000017 12315063430 022322 0 ustar anay anay 0000000 0000000 buildnotifylib
BuildNotify-0.3.5/BuildNotify.egg-info/dependency_links.txt 0000664 0001750 0001750 00000000001 12315063430 023640 0 ustar anay anay 0000000 0000000
BuildNotify-0.3.5/BuildNotify.egg-info/PKG-INFO 0000664 0001750 0001750 00000001135 12315063430 020667 0 ustar anay anay 0000000 0000000 Metadata-Version: 1.1
Name: BuildNotify
Version: 0.3.5
Summary: Cruise Control build monitor for Windows/Linux/Mac
Home-page: http://bitbucket.org/Anay/buildnotify/
Author: Anay Nayak
Author-email: anayak007@gmail.com
License: GPL v3
Description: BuildNotify is a cruise control system tray monitor which works on Windows/Linux/Mac.It was largely inspired from CCMenu and lets you monitor multiple continuous integration servers withcustomizable build notifications for all projects
Keywords: cctray ccmenu buildnotify ubuntu linux cruisecontrol continuous integration ci
Platform: UNKNOWN
Requires: pytz
BuildNotify-0.3.5/BuildNotify.egg-info/SOURCES.txt 0000664 0001750 0001750 00000001622 12315063430 021457 0 ustar anay anay 0000000 0000000 MANIFEST.in
README
buildnotifyapplet.py
setup.py
BuildNotify.egg-info/PKG-INFO
BuildNotify.egg-info/SOURCES.txt
BuildNotify.egg-info/dependency_links.txt
BuildNotify.egg-info/top_level.txt
buildnotifylib/__init__.py
buildnotifylib/app_menu.py
buildnotifylib/app_notification.py
buildnotifylib/app_ui.py
buildnotifylib/build_icons.py
buildnotifylib/buildnotify.py
buildnotifylib/config.py
buildnotifylib/notifications.py
buildnotifylib/preferences.py
buildnotifylib/project_status_notification.py
buildnotifylib/server_configuration_dialog.py
buildnotifylib/version.py
buildnotifylib/core/__init__.py
buildnotifylib/core/distance_of_time.py
buildnotifylib/core/http_connection.py
buildnotifylib/core/projects.py
buildnotifylib/core/timed_event.py
buildnotifylib/generated/__init__.py
buildnotifylib/generated/icons_rc.py
buildnotifylib/generated/preferences_ui.py
buildnotifylib/generated/server_configuration_ui.py BuildNotify-0.3.5/PKG-INFO 0000664 0001750 0001750 00000001135 12315063430 014745 0 ustar anay anay 0000000 0000000 Metadata-Version: 1.1
Name: BuildNotify
Version: 0.3.5
Summary: Cruise Control build monitor for Windows/Linux/Mac
Home-page: http://bitbucket.org/Anay/buildnotify/
Author: Anay Nayak
Author-email: anayak007@gmail.com
License: GPL v3
Description: BuildNotify is a cruise control system tray monitor which works on Windows/Linux/Mac.It was largely inspired from CCMenu and lets you monitor multiple continuous integration servers withcustomizable build notifications for all projects
Keywords: cctray ccmenu buildnotify ubuntu linux cruisecontrol continuous integration ci
Platform: UNKNOWN
Requires: pytz
BuildNotify-0.3.5/setup.cfg 0000664 0001750 0001750 00000000073 12315063430 015471 0 ustar anay anay 0000000 0000000 [egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
BuildNotify-0.3.5/buildnotifylib/ 0000755 0001750 0001750 00000000000 12315063430 016665 5 ustar anay anay 0000000 0000000 BuildNotify-0.3.5/buildnotifylib/generated/ 0000755 0001750 0001750 00000000000 12315063430 020623 5 ustar anay anay 0000000 0000000 BuildNotify-0.3.5/buildnotifylib/generated/server_configuration_ui.py 0000644 0001750 0001750 00000012707 12315063423 026140 0 ustar anay anay 0000000 0000000 # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'data/server_configuration.ui'
#
# Created: Tue Mar 18 20:49:08 2014
# by: PyQt4 UI code generator 4.9.3
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
class Ui_serverConfigurationDialog(object):
def setupUi(self, serverConfigurationDialog):
serverConfigurationDialog.setObjectName(_fromUtf8("serverConfigurationDialog"))
serverConfigurationDialog.resize(440, 381)
self.projectsList = QtGui.QListView(serverConfigurationDialog)
self.projectsList.setGeometry(QtCore.QRect(20, 80, 401, 191))
self.projectsList.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.projectsList.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
self.projectsList.setObjectName(_fromUtf8("projectsList"))
self.label = QtGui.QLabel(serverConfigurationDialog)
self.label.setGeometry(QtCore.QRect(20, 60, 391, 20))
self.label.setObjectName(_fromUtf8("label"))
self.cctrayUrlLabel = QtGui.QLabel(serverConfigurationDialog)
self.cctrayUrlLabel.setGeometry(QtCore.QRect(20, 0, 161, 41))
self.cctrayUrlLabel.setObjectName(_fromUtf8("cctrayUrlLabel"))
self.addServerUrl = QtGui.QLineEdit(serverConfigurationDialog)
self.addServerUrl.setGeometry(QtCore.QRect(20, 30, 311, 30))
self.addServerUrl.setObjectName(_fromUtf8("addServerUrl"))
self.loadUrlButton = QtGui.QPushButton(serverConfigurationDialog)
self.loadUrlButton.setGeometry(QtCore.QRect(340, 30, 81, 31))
self.loadUrlButton.setAutoDefault(False)
self.loadUrlButton.setObjectName(_fromUtf8("loadUrlButton"))
self.submitButton = QtGui.QPushButton(serverConfigurationDialog)
self.submitButton.setGeometry(QtCore.QRect(340, 340, 81, 31))
self.submitButton.setAutoDefault(False)
self.submitButton.setObjectName(_fromUtf8("submitButton"))
self.layoutWidget = QtGui.QWidget(serverConfigurationDialog)
self.layoutWidget.setGeometry(QtCore.QRect(20, 280, 401, 41))
self.layoutWidget.setObjectName(_fromUtf8("layoutWidget"))
self.horizontalLayout = QtGui.QHBoxLayout(self.layoutWidget)
self.horizontalLayout.setSizeConstraint(QtGui.QLayout.SetFixedSize)
self.horizontalLayout.setMargin(0)
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.timezoneLabel = QtGui.QLabel(self.layoutWidget)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.timezoneLabel.sizePolicy().hasHeightForWidth())
self.timezoneLabel.setSizePolicy(sizePolicy)
self.timezoneLabel.setMinimumSize(QtCore.QSize(180, 0))
self.timezoneLabel.setMaximumSize(QtCore.QSize(180, 16777215))
self.timezoneLabel.setObjectName(_fromUtf8("timezoneLabel"))
self.horizontalLayout.addWidget(self.timezoneLabel)
self.timezoneList = QtGui.QComboBox(self.layoutWidget)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.timezoneList.sizePolicy().hasHeightForWidth())
self.timezoneList.setSizePolicy(sizePolicy)
self.timezoneList.setMinimumSize(QtCore.QSize(210, 0))
self.timezoneList.setMaximumSize(QtCore.QSize(200, 16777215))
self.timezoneList.setObjectName(_fromUtf8("timezoneList"))
self.horizontalLayout.addWidget(self.timezoneList)
self.label.setBuddy(self.projectsList)
self.cctrayUrlLabel.setBuddy(self.addServerUrl)
self.timezoneLabel.setBuddy(self.timezoneList)
self.retranslateUi(serverConfigurationDialog)
QtCore.QObject.connect(self.addServerUrl, QtCore.SIGNAL(_fromUtf8("returnPressed()")), self.loadUrlButton.click)
QtCore.QObject.connect(self.submitButton, QtCore.SIGNAL(_fromUtf8("clicked()")), serverConfigurationDialog.accept)
QtCore.QMetaObject.connectSlotsByName(serverConfigurationDialog)
serverConfigurationDialog.setTabOrder(self.addServerUrl, self.loadUrlButton)
serverConfigurationDialog.setTabOrder(self.loadUrlButton, self.submitButton)
serverConfigurationDialog.setTabOrder(self.submitButton, self.projectsList)
def retranslateUi(self, serverConfigurationDialog):
serverConfigurationDialog.setWindowTitle(QtGui.QApplication.translate("serverConfigurationDialog", "Add Server", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("serverConfigurationDialog", "Select projects", None, QtGui.QApplication.UnicodeUTF8))
self.cctrayUrlLabel.setText(QtGui.QApplication.translate("serverConfigurationDialog", "Path to cctray.xml", None, QtGui.QApplication.UnicodeUTF8))
self.loadUrlButton.setText(QtGui.QApplication.translate("serverConfigurationDialog", "Load", None, QtGui.QApplication.UnicodeUTF8))
self.submitButton.setText(QtGui.QApplication.translate("serverConfigurationDialog", "OK", None, QtGui.QApplication.UnicodeUTF8))
self.timezoneLabel.setText(QtGui.QApplication.translate("serverConfigurationDialog", "Server timezone", None, QtGui.QApplication.UnicodeUTF8))
BuildNotify-0.3.5/buildnotifylib/generated/icons_rc.py 0000644 0001750 0001750 00000015053 12315063423 023002 0 ustar anay anay 0000000 0000000 # -*- coding: utf-8 -*-
# Resource object code
#
# Created: Tue Mar 18 20:49:08 2014
# by: The Resource Compiler for PyQt (Qt v4.8.2)
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore
qt_resource_data = "\
\x00\x00\x00\xcd\
\x3c\
\x73\x76\x67\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\
\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\
\x30\x2f\x73\x76\x67\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\
\x31\x2e\x31\x22\x3e\x0a\x20\x20\x3c\x72\x65\x63\x74\x20\x78\x3d\
\x22\x30\x22\x20\x79\x3d\x22\x30\x22\x20\x72\x78\x3d\x22\x31\x35\
\x30\x22\x20\x72\x79\x3d\x22\x31\x35\x30\x22\x20\x77\x69\x64\x74\
\x68\x3d\x22\x37\x34\x34\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\
\x37\x34\x34\x22\x0a\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\
\x6c\x6c\x3a\x72\x67\x62\x28\x31\x34\x36\x2c\x32\x30\x38\x2c\x38\
\x30\x29\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x62\x6c\x61\x63\x6b\x3b\
\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x35\x3b\x73\
\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x30\x2e\
\x35\x22\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
\x00\x00\x00\xcd\
\x3c\
\x73\x76\x67\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\
\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\
\x30\x2f\x73\x76\x67\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\
\x31\x2e\x31\x22\x3e\x0a\x20\x20\x3c\x72\x65\x63\x74\x20\x78\x3d\
\x22\x30\x22\x20\x79\x3d\x22\x30\x22\x20\x72\x78\x3d\x22\x31\x35\
\x30\x22\x20\x72\x79\x3d\x22\x31\x35\x30\x22\x20\x77\x69\x64\x74\
\x68\x3d\x22\x37\x34\x34\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\
\x37\x34\x34\x22\x0a\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\
\x6c\x6c\x3a\x72\x67\x62\x28\x31\x34\x36\x2c\x32\x30\x38\x2c\x38\
\x30\x29\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x62\x6c\x61\x63\x6b\x3b\
\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x35\x3b\x73\
\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x30\x2e\
\x35\x22\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
\x00\x00\x00\xce\
\x3c\
\x73\x76\x67\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\
\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\
\x30\x2f\x73\x76\x67\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\
\x31\x2e\x31\x22\x3e\x0a\x20\x20\x3c\x72\x65\x63\x74\x20\x78\x3d\
\x22\x30\x22\x20\x79\x3d\x22\x30\x22\x20\x72\x78\x3d\x22\x31\x35\
\x30\x22\x20\x72\x79\x3d\x22\x31\x35\x30\x22\x20\x77\x69\x64\x74\
\x68\x3d\x22\x37\x34\x34\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\
\x37\x34\x34\x22\x0a\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\
\x6c\x6c\x3a\x72\x67\x62\x28\x31\x30\x32\x2c\x31\x30\x32\x2c\x31\
\x30\x32\x29\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x62\x6c\x61\x63\x6b\
\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x35\x3b\
\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x30\
\x2e\x35\x22\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
\x00\x00\x00\xcc\
\x3c\
\x73\x76\x67\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\
\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\
\x30\x2f\x73\x76\x67\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\
\x31\x2e\x31\x22\x3e\x0a\x20\x20\x3c\x72\x65\x63\x74\x20\x78\x3d\
\x22\x30\x22\x20\x79\x3d\x22\x30\x22\x20\x72\x78\x3d\x22\x31\x35\
\x30\x22\x20\x72\x79\x3d\x22\x31\x35\x30\x22\x20\x77\x69\x64\x74\
\x68\x3d\x22\x37\x34\x34\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\
\x37\x34\x34\x22\x0a\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\
\x6c\x6c\x3a\x72\x67\x62\x28\x32\x35\x35\x2c\x31\x35\x33\x2c\x30\
\x29\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x62\x6c\x61\x63\x6b\x3b\x73\
\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x35\x3b\x73\x74\
\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x30\x2e\x35\
\x22\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
\x00\x00\x00\xc1\
\x3c\
\x73\x76\x67\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\
\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\
\x30\x2f\x73\x76\x67\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\
\x31\x2e\x31\x22\x3e\x0a\x20\x20\x3c\x72\x65\x63\x74\x20\x78\x3d\
\x22\x30\x22\x20\x79\x3d\x22\x30\x22\x20\x72\x78\x3d\x22\x31\x35\
\x30\x22\x20\x72\x79\x3d\x22\x31\x35\x30\x22\x20\x77\x69\x64\x74\
\x68\x3d\x22\x37\x34\x34\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\
\x37\x34\x34\x22\x0a\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\
\x6c\x6c\x3a\x72\x65\x64\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x62\x6c\
\x61\x63\x6b\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\
\x3a\x35\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\
\x79\x3a\x30\x2e\x35\x22\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
\
"
qt_resource_name = "\
\x00\x06\
\x07\xaa\x8b\xc3\
\x00\x73\
\x00\x74\x00\x61\x00\x74\x00\x75\x00\x73\
\x00\x05\
\x00\x6f\xa6\x53\
\x00\x69\
\x00\x63\x00\x6f\x00\x6e\x00\x73\
\x00\x17\
\x02\x27\x97\xc7\
\x00\x62\
\x00\x75\x00\x69\x00\x6c\x00\x64\x00\x6e\x00\x6f\x00\x74\x00\x69\x00\x66\x00\x79\x00\x2d\x00\x73\x00\x75\x00\x63\x00\x63\x00\x65\
\x00\x73\x00\x73\x00\x2e\x00\x73\x00\x76\x00\x67\
\x00\x20\
\x02\xe1\xd6\x67\
\x00\x62\
\x00\x75\x00\x69\x00\x6c\x00\x64\x00\x6e\x00\x6f\x00\x74\x00\x69\x00\x66\x00\x79\x00\x2d\x00\x73\x00\x75\x00\x63\x00\x63\x00\x65\
\x00\x73\x00\x73\x00\x2d\x00\x62\x00\x75\x00\x69\x00\x6c\x00\x64\x00\x69\x00\x6e\x00\x67\x00\x2e\x00\x73\x00\x76\x00\x67\
\x00\x18\
\x06\x07\x4c\x67\
\x00\x62\
\x00\x75\x00\x69\x00\x6c\x00\x64\x00\x6e\x00\x6f\x00\x74\x00\x69\x00\x66\x00\x79\x00\x2d\x00\x69\x00\x6e\x00\x61\x00\x63\x00\x74\
\x00\x69\x00\x76\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
\x00\x20\
\x03\xb9\xe4\x87\
\x00\x62\
\x00\x75\x00\x69\x00\x6c\x00\x64\x00\x6e\x00\x6f\x00\x74\x00\x69\x00\x66\x00\x79\x00\x2d\x00\x66\x00\x61\x00\x69\x00\x6c\x00\x75\
\x00\x72\x00\x65\x00\x2d\x00\x62\x00\x75\x00\x69\x00\x6c\x00\x64\x00\x69\x00\x6e\x00\x67\x00\x2e\x00\x73\x00\x76\x00\x67\
\x00\x17\
\x02\xec\x1c\x87\
\x00\x62\
\x00\x75\x00\x69\x00\x6c\x00\x64\x00\x6e\x00\x6f\x00\x74\x00\x69\x00\x66\x00\x79\x00\x2d\x00\x66\x00\x61\x00\x69\x00\x6c\x00\x75\
\x00\x72\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
"
qt_resource_struct = "\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
\x00\x00\x00\x12\x00\x02\x00\x00\x00\x05\x00\x00\x00\x03\
\x00\x00\x00\x22\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x00\x56\x00\x00\x00\x00\x00\x01\x00\x00\x00\xd1\
\x00\x00\x01\x18\x00\x00\x00\x00\x00\x01\x00\x00\x03\x44\
\x00\x00\x00\xd2\x00\x00\x00\x00\x00\x01\x00\x00\x02\x74\
\x00\x00\x00\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x01\xa2\
"
def qInitResources():
QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
def qCleanupResources():
QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
qInitResources()
BuildNotify-0.3.5/buildnotifylib/generated/__init__.py 0000644 0001750 0001750 00000000024 12315063423 022732 0 ustar anay anay 0000000 0000000 __author__ = 'anay'
BuildNotify-0.3.5/buildnotifylib/generated/preferences_ui.py 0000644 0001750 0001750 00000027330 12315063423 024202 0 ustar anay anay 0000000 0000000 # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'data/preferences.ui'
#
# Created: Tue Mar 18 20:49:08 2014
# by: PyQt4 UI code generator 4.9.3
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
class Ui_Preferences(object):
def setupUi(self, Preferences):
Preferences.setObjectName(_fromUtf8("Preferences"))
Preferences.resize(470, 394)
Preferences.setSizeGripEnabled(False)
self.tabWidget = QtGui.QTabWidget(Preferences)
self.tabWidget.setGeometry(QtCore.QRect(10, 10, 451, 331))
self.tabWidget.setObjectName(_fromUtf8("tabWidget"))
self.serversTab = QtGui.QWidget()
self.serversTab.setObjectName(_fromUtf8("serversTab"))
self.groupBox_2 = QtGui.QGroupBox(self.serversTab)
self.groupBox_2.setGeometry(QtCore.QRect(10, 10, 431, 271))
self.groupBox_2.setObjectName(_fromUtf8("groupBox_2"))
self.cctrayPathList = QtGui.QListView(self.groupBox_2)
self.cctrayPathList.setGeometry(QtCore.QRect(0, 21, 419, 211))
self.cctrayPathList.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.cctrayPathList.setObjectName(_fromUtf8("cctrayPathList"))
self.addButton = QtGui.QPushButton(self.groupBox_2)
self.addButton.setGeometry(QtCore.QRect(380, 240, 41, 31))
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.addButton.sizePolicy().hasHeightForWidth())
self.addButton.setSizePolicy(sizePolicy)
self.addButton.setObjectName(_fromUtf8("addButton"))
self.removeButton = QtGui.QPushButton(self.groupBox_2)
self.removeButton.setGeometry(QtCore.QRect(330, 240, 41, 31))
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.removeButton.sizePolicy().hasHeightForWidth())
self.removeButton.setSizePolicy(sizePolicy)
self.removeButton.setObjectName(_fromUtf8("removeButton"))
self.configureProjectButton = QtGui.QPushButton(self.groupBox_2)
self.configureProjectButton.setEnabled(False)
self.configureProjectButton.setGeometry(QtCore.QRect(200, 240, 116, 30))
self.configureProjectButton.setObjectName(_fromUtf8("configureProjectButton"))
self.tabWidget.addTab(self.serversTab, _fromUtf8(""))
self.notificationsTab = QtGui.QWidget()
self.notificationsTab.setObjectName(_fromUtf8("notificationsTab"))
self.groupBox = QtGui.QGroupBox(self.notificationsTab)
self.groupBox.setGeometry(QtCore.QRect(10, 10, 421, 131))
self.groupBox.setFlat(False)
self.groupBox.setCheckable(False)
self.groupBox.setObjectName(_fromUtf8("groupBox"))
self.layoutWidget_2 = QtGui.QWidget(self.groupBox)
self.layoutWidget_2.setGeometry(QtCore.QRect(0, 30, 401, 101))
self.layoutWidget_2.setObjectName(_fromUtf8("layoutWidget_2"))
self.gridLayout_2 = QtGui.QGridLayout(self.layoutWidget_2)
self.gridLayout_2.setMargin(0)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.successfulBuildsCheckbox = QtGui.QCheckBox(self.layoutWidget_2)
self.successfulBuildsCheckbox.setObjectName(_fromUtf8("successfulBuildsCheckbox"))
self.gridLayout_2.addWidget(self.successfulBuildsCheckbox, 0, 0, 1, 1)
self.brokenBuildsCheckbox = QtGui.QCheckBox(self.layoutWidget_2)
self.brokenBuildsCheckbox.setObjectName(_fromUtf8("brokenBuildsCheckbox"))
self.gridLayout_2.addWidget(self.brokenBuildsCheckbox, 0, 1, 1, 1)
self.fixedBuildsCheckbox = QtGui.QCheckBox(self.layoutWidget_2)
self.fixedBuildsCheckbox.setObjectName(_fromUtf8("fixedBuildsCheckbox"))
self.gridLayout_2.addWidget(self.fixedBuildsCheckbox, 1, 0, 1, 1)
self.stillFailingBuildsCheckbox = QtGui.QCheckBox(self.layoutWidget_2)
self.stillFailingBuildsCheckbox.setObjectName(_fromUtf8("stillFailingBuildsCheckbox"))
self.gridLayout_2.addWidget(self.stillFailingBuildsCheckbox, 1, 1, 1, 1)
self.connectivityIssuesCheckbox = QtGui.QCheckBox(self.layoutWidget_2)
self.connectivityIssuesCheckbox.setMaximumSize(QtCore.QSize(200, 16777215))
self.connectivityIssuesCheckbox.setObjectName(_fromUtf8("connectivityIssuesCheckbox"))
self.gridLayout_2.addWidget(self.connectivityIssuesCheckbox, 2, 0, 1, 1)
self.groupBox_3 = QtGui.QGroupBox(self.notificationsTab)
self.groupBox_3.setGeometry(QtCore.QRect(10, 160, 401, 111))
self.groupBox_3.setObjectName(_fromUtf8("groupBox_3"))
self.scriptCheckbox = QtGui.QCheckBox(self.groupBox_3)
self.scriptCheckbox.setGeometry(QtCore.QRect(0, 20, 401, 31))
self.scriptCheckbox.setObjectName(_fromUtf8("scriptCheckbox"))
self.horizontalLayoutWidget_2 = QtGui.QWidget(self.groupBox_3)
self.horizontalLayoutWidget_2.setGeometry(QtCore.QRect(10, 50, 391, 51))
self.horizontalLayoutWidget_2.setObjectName(_fromUtf8("horizontalLayoutWidget_2"))
self.horizontalLayout_3 = QtGui.QHBoxLayout(self.horizontalLayoutWidget_2)
self.horizontalLayout_3.setMargin(0)
self.horizontalLayout_3.setObjectName(_fromUtf8("horizontalLayout_3"))
self.scriptLabel = QtGui.QLabel(self.horizontalLayoutWidget_2)
self.scriptLabel.setObjectName(_fromUtf8("scriptLabel"))
self.horizontalLayout_3.addWidget(self.scriptLabel)
self.scriptLineEdit = QtGui.QLineEdit(self.horizontalLayoutWidget_2)
self.scriptLineEdit.setEnabled(False)
self.scriptLineEdit.setText(_fromUtf8(""))
self.scriptLineEdit.setObjectName(_fromUtf8("scriptLineEdit"))
self.horizontalLayout_3.addWidget(self.scriptLineEdit)
self.tabWidget.addTab(self.notificationsTab, _fromUtf8(""))
self.miscTab = QtGui.QWidget()
self.miscTab.setObjectName(_fromUtf8("miscTab"))
self.showLastBuildTimeCheckbox = QtGui.QCheckBox(self.miscTab)
self.showLastBuildTimeCheckbox.setGeometry(QtCore.QRect(10, 60, 351, 31))
self.showLastBuildTimeCheckbox.setObjectName(_fromUtf8("showLastBuildTimeCheckbox"))
self.horizontalLayoutWidget = QtGui.QWidget(self.miscTab)
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 421, 41))
self.horizontalLayoutWidget.setObjectName(_fromUtf8("horizontalLayoutWidget"))
self.horizontalLayout_2 = QtGui.QHBoxLayout(self.horizontalLayoutWidget)
self.horizontalLayout_2.setMargin(0)
self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2"))
self.pollingIntervalLabel = QtGui.QLabel(self.horizontalLayoutWidget)
self.pollingIntervalLabel.setObjectName(_fromUtf8("pollingIntervalLabel"))
self.horizontalLayout_2.addWidget(self.pollingIntervalLabel)
self.pollingIntervalSpinBox = QtGui.QSpinBox(self.horizontalLayoutWidget)
self.pollingIntervalSpinBox.setMinimumSize(QtCore.QSize(130, 0))
self.pollingIntervalSpinBox.setMaximumSize(QtCore.QSize(130, 16777215))
self.pollingIntervalSpinBox.setWrapping(False)
self.pollingIntervalSpinBox.setMinimum(1)
self.pollingIntervalSpinBox.setMaximum(60)
self.pollingIntervalSpinBox.setSingleStep(1)
self.pollingIntervalSpinBox.setObjectName(_fromUtf8("pollingIntervalSpinBox"))
self.horizontalLayout_2.addWidget(self.pollingIntervalSpinBox)
self.tabWidget.addTab(self.miscTab, _fromUtf8(""))
self.buttonBox = QtGui.QDialogButtonBox(Preferences)
self.buttonBox.setGeometry(QtCore.QRect(40, 350, 421, 32))
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
self.scriptLabel.setBuddy(self.scriptLineEdit)
self.pollingIntervalLabel.setBuddy(self.pollingIntervalSpinBox)
self.retranslateUi(Preferences)
self.tabWidget.setCurrentIndex(0)
QtCore.QObject.connect(self.scriptCheckbox, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.scriptLineEdit.setEnabled)
QtCore.QMetaObject.connectSlotsByName(Preferences)
def retranslateUi(self, Preferences):
Preferences.setWindowTitle(QtGui.QApplication.translate("Preferences", "Preferences", None, QtGui.QApplication.UnicodeUTF8))
self.groupBox_2.setTitle(QtGui.QApplication.translate("Preferences", "Monitored servers", None, QtGui.QApplication.UnicodeUTF8))
self.addButton.setToolTip(QtGui.QApplication.translate("Preferences", "Add", None, QtGui.QApplication.UnicodeUTF8))
self.addButton.setText(QtGui.QApplication.translate("Preferences", "+", None, QtGui.QApplication.UnicodeUTF8))
self.removeButton.setToolTip(QtGui.QApplication.translate("Preferences", "Remove", None, QtGui.QApplication.UnicodeUTF8))
self.removeButton.setText(QtGui.QApplication.translate("Preferences", "-", None, QtGui.QApplication.UnicodeUTF8))
self.configureProjectButton.setText(QtGui.QApplication.translate("Preferences", "Configure", None, QtGui.QApplication.UnicodeUTF8))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.serversTab), QtGui.QApplication.translate("Preferences", "Servers", None, QtGui.QApplication.UnicodeUTF8))
self.groupBox.setTitle(QtGui.QApplication.translate("Preferences", "Notification settings", None, QtGui.QApplication.UnicodeUTF8))
self.successfulBuildsCheckbox.setText(QtGui.QApplication.translate("Preferences", "successful builds", None, QtGui.QApplication.UnicodeUTF8))
self.brokenBuildsCheckbox.setText(QtGui.QApplication.translate("Preferences", "broken builds", None, QtGui.QApplication.UnicodeUTF8))
self.fixedBuildsCheckbox.setText(QtGui.QApplication.translate("Preferences", "fixed builds", None, QtGui.QApplication.UnicodeUTF8))
self.stillFailingBuildsCheckbox.setText(QtGui.QApplication.translate("Preferences", "still failing builds", None, QtGui.QApplication.UnicodeUTF8))
self.connectivityIssuesCheckbox.setText(QtGui.QApplication.translate("Preferences", "connectivity issues", None, QtGui.QApplication.UnicodeUTF8))
self.groupBox_3.setTitle(QtGui.QApplication.translate("Preferences", "Custom notifications", None, QtGui.QApplication.UnicodeUTF8))
self.scriptCheckbox.setText(QtGui.QApplication.translate("Preferences", "Execute script for notifications", None, QtGui.QApplication.UnicodeUTF8))
self.scriptLabel.setText(QtGui.QApplication.translate("Preferences", "Script", None, QtGui.QApplication.UnicodeUTF8))
self.scriptLineEdit.setToolTip(QtGui.QApplication.translate("Preferences", "#status# and #projects# would be replaced by the build status and projects respectively", None, QtGui.QApplication.UnicodeUTF8))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.notificationsTab), QtGui.QApplication.translate("Preferences", "Notifications", None, QtGui.QApplication.UnicodeUTF8))
self.showLastBuildTimeCheckbox.setText(QtGui.QApplication.translate("Preferences", "show last build time for each project", None, QtGui.QApplication.UnicodeUTF8))
self.pollingIntervalLabel.setText(QtGui.QApplication.translate("Preferences", "Server polling interval", None, QtGui.QApplication.UnicodeUTF8))
self.pollingIntervalSpinBox.setSuffix(QtGui.QApplication.translate("Preferences", " minutes", None, QtGui.QApplication.UnicodeUTF8))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.miscTab), QtGui.QApplication.translate("Preferences", "Misc", None, QtGui.QApplication.UnicodeUTF8))
import icons_rc
BuildNotify-0.3.5/buildnotifylib/preferences.py 0000644 0001750 0001750 00000007633 12315063423 021553 0 ustar anay anay 0000000 0000000 from PyQt4 import QtCore
from PyQt4 import QtGui
from buildnotifylib.generated.preferences_ui import Ui_Preferences
from server_configuration_dialog import ServerConfigurationDialog
class PreferencesDialog(QtGui.QDialog):
addServerTemplateText = "http://[host]:[port]/dashboard/cctray.xml"
def __init__(self, conf, parent=None):
QtGui.QDialog.__init__(self, parent)
self.conf = conf
self.ui = Ui_Preferences()
self.ui.setupUi(self)
self.checkboxes = dict(successfulBuild=self.ui.successfulBuildsCheckbox, brokenBuild=self.ui.brokenBuildsCheckbox, fixedBuild=self.ui.fixedBuildsCheckbox,
stillFailingBuild=self.ui.stillFailingBuildsCheckbox, connectivityIssues=self.ui.connectivityIssuesCheckbox, lastBuildTimeForProject=self.ui.showLastBuildTimeCheckbox)
self.set_values_from_config()
# Connect up the buttons.
self.connect(self.ui.addButton, QtCore.SIGNAL("clicked()"), self.add_server)
self.connect(self.ui.removeButton, QtCore.SIGNAL("clicked()"), self.remove_element)
self.connect(self.ui.buttonBox, QtCore.SIGNAL("accepted()"), QtCore.SLOT("accept()"))
self.connect(self.ui.configureProjectButton, QtCore.SIGNAL("clicked()"), self.configure_projects)
def set_values_from_config(self):
self.cctray_urls_model = QtGui.QStringListModel(self.conf.get_urls())
self.ui.cctrayPathList.setModel(self.cctray_urls_model)
self.ui.cctrayPathList.clicked.connect(lambda x: self.item_selection_changed(True))
self.ui.removeButton.clicked.connect(lambda x: self.item_selection_changed(False))
for key, checkbox in self.checkboxes.iteritems():
checkbox.setChecked(self.conf.get_value(str(key)))
self.ui.pollingIntervalSpinBox.setValue(self.conf.get_interval())
self.ui.scriptCheckbox.setChecked(self.conf.get_custom_script_enabled())
self.ui.scriptLineEdit.setText(self.conf.get_custom_script())
def item_selection_changed(self, status):
self.ui.configureProjectButton.setEnabled(status)
def add_server(self):
server_configuration_dialog = ServerConfigurationDialog(True, self.addServerTemplateText, self.conf, self)
if server_configuration_dialog.exec_() == QtGui.QDialog.Accepted:
url = server_configuration_dialog.save()
urls = self.ui.cctrayPathList.model().stringList()
urls.append(url)
self.cctray_urls_model = QtGui.QStringListModel(urls)
self.ui.cctrayPathList.setModel(self.cctray_urls_model)
def remove_element(self):
index = self.ui.cctrayPathList.selectionModel().currentIndex()
urls = self.ui.cctrayPathList.model().stringList()
urls.removeAt(index.row())
self.cctray_urls_model = QtGui.QStringListModel(urls)
self.ui.cctrayPathList.setModel(self.cctray_urls_model)
def configure_projects(self):
url = str(self.ui.cctrayPathList.selectionModel().currentIndex().data().toString())
if not url:
return
server_configuration_dialog = ServerConfigurationDialog(False, url, self.conf, self)
if server_configuration_dialog.exec_() == QtGui.QDialog.Accepted:
server_configuration_dialog.save()
def get_urls(self):
return self.ui.cctrayPathList.model().stringList()
def get_interval(self):
return self.ui.pollingIntervalSpinBox.value()
def get_selections(self):
return map(lambda (key, checkbox): (key, checkbox.isChecked()), self.checkboxes.items())
def save(self):
self.conf.update_urls(self.get_urls())
self.conf.set_interval(self.get_interval())
self.conf.set_custom_script(self.ui.scriptLineEdit.text(), self.ui.scriptCheckbox.isChecked())
self.conf.set_custom_script_enabled(self.ui.scriptCheckbox.isChecked())
for key, value in self.get_selections():
self.conf.set_value(key, value)
BuildNotify-0.3.5/buildnotifylib/config.py 0000644 0001750 0001750 00000006137 12315063423 020515 0 ustar anay anay 0000000 0000000 from PyQt4 import QtCore
class Config:
default_options = dict(successfulBuild=False, brokenBuild=True, fixedBuild=True, stillFailingBuild=True, connectivityIssues=True, lastBuildTimeForProject=True)
default_script = "echo #status# #projects# >> /tmp/buildnotify.log"
CUSTOM_SCRIPT = "notifications/custom_script"
SCRIPT_ENABLED = "notifications/custom_script_enabled"
INTERVAL_IN_MINUTES = "connection/interval_in_minutes"
CONNECTION_URLS = "connection/urls"
EXCLUDES = "excludes/%s"
TIMEZONE = "timezone/%s"
VALUES = "values/%s"
def __init__(self):
self.settings = QtCore.QSettings("BuildNotify", "BuildNotify")
self.timeout = self.get_with_default("connection/timeout", 10).toDouble()[0]
self.interval = self.get_with_default(self.INTERVAL_IN_MINUTES, 2).toInt()[0]
def get_with_default(self, key, default):
if str(self.settings.value(key, "notset").toString()) == "notset":
self.settings.setValue(key, default)
return self.settings.value(key)
def add_server_url(self, url):
urls = self.get_urls()
urls.append(url)
self.update_urls(urls)
def update_urls(self, urls):
self.settings.setValue(self.CONNECTION_URLS, urls)
def get_urls(self):
return self.settings.value(self.CONNECTION_URLS, QtCore.QStringList()).toStringList()
def set_interval(self, interval):
self.settings.setValue(self.INTERVAL_IN_MINUTES, interval)
def get_interval(self):
return self.get_with_default(self.INTERVAL_IN_MINUTES, 2).toInt()[0]
def get_interval_in_millis(self):
return self.get_interval() * 1000 * 60
def get_value(self, key):
return self.get_with_default(self.VALUES % key, self.default_options[key]).toBool()
def set_value(self, key, value):
return self.settings.setValue(self.VALUES % key, value)
def get_timezone(self, url):
return str(self.get_with_default(self.TIMEZONE % url, "US/Central").toString())
def get_project_timezone(self, url, server_url):
# project level time zones can not be edited, so ditch the value
# and just return the server's time zone
return self.get_timezone(server_url)
def set_project_timezone(self, url, timezone):
self.settings.setValue(self.TIMEZONE % url, timezone)
def set_project_excludes(self, url, excluded_project_names):
self.settings.setValue(self.EXCLUDES % url, excluded_project_names)
def get_project_excludes(self, url):
return self.settings.value(self.EXCLUDES % url, QtCore.QStringList()).toStringList()
def set_custom_script(self, user_script, status):
script = user_script if status else self.default_script
self.settings.setValue(self.CUSTOM_SCRIPT, script)
def set_custom_script_enabled(self, status):
self.settings.setValue(self.SCRIPT_ENABLED, status)
def get_custom_script(self):
return str(self.settings.value(self.CUSTOM_SCRIPT, self.default_script).toString())
def get_custom_script_enabled(self):
return self.settings.value(self.SCRIPT_ENABLED, False).toBool()
BuildNotify-0.3.5/buildnotifylib/core/ 0000755 0001750 0001750 00000000000 12315063430 017615 5 ustar anay anay 0000000 0000000 BuildNotify-0.3.5/buildnotifylib/core/projects.py 0000644 0001750 0001750 00000010612 12315063423 022022 0 ustar anay anay 0000000 0000000 from xml.dom import minidom
from http_connection import HttpConnection
from dateutil.parser import parse
from PyQt4.QtCore import QThread
from PyQt4 import QtCore
from timed_event import BackgroundEvent
class Project:
def __init__(self, props):
self.name = props['name']
self.status = props['lastBuildStatus']
self.activity = props['activity']
self.last_build_time = parse(props['lastBuildTime']).replace(tzinfo=None)
self.url = props['url']
self.server_url = props['server_url']
def get_build_status(self):
return self.status + "." + self.activity
class ContinuousIntegrationServer:
def __init__(self, url, projects, unavailable=False):
self.url = url
self.projects = projects
self.unavailable = unavailable
def get_projects(self):
return self.projects
class FilteredContinuousIntegrationServer:
def __init__(self, server, filter_projects):
self.server = server
self.filter_projects = filter_projects
self.unavailable = server.unavailable
self.url = server.url
def get_projects(self):
return filter(lambda project: project.name not in self.filter_projects, self.server.get_projects())
class OverallIntegrationStatus:
def __init__(self, servers):
self.servers = servers
def get_build_status(self):
build_status_mapping = self.to_map()
seq = ['Failure.Building', 'Failure.Sleeping', 'Success.Building', 'Success.Sleeping', 'Failure.CheckingModifications', 'Success.CheckingModifications']
for status in seq:
if len(build_status_mapping[status]) > 0:
return status
return None
def get_failing_builds(self):
return filter(lambda p: p.status == 'Failure', self.get_projects())
def to_map(self):
status = dict(
[('Success.Sleeping', []), ('Success.Building', []), ('Failure.CheckingModifications', []), ('Success.CheckingModifications', []), ('Failure.Sleeping', []), ('Failure.Building', []),
('Unknown.Building', []), ('Unknown.CheckingModifications', []), ('Unknown.Sleeping', []), ('Unknown.Unknown', [])])
for project in self.get_projects():
if project.get_build_status() in status:
status[project.get_build_status()].append(project)
else:
status['Unknown.Unknown'].append(project)
return status
def get_projects(self):
all_projects = []
for server in self.servers:
if server.get_projects() is not None:
all_projects.extend(server.get_projects())
return all_projects
def unavailable_servers(self):
return filter(lambda server: server.unavailable, self.servers)
class ProjectsPopulator(QThread):
def __init__(self, config, parent=None):
QThread.__init__(self, parent)
self.config = config
self.listeners = []
def load_from_server(self):
self.start()
def reload(self):
BackgroundEvent(self.process, self).run()
def process(self):
overall_status = []
for url in self.config.get_urls():
overall_status.append(self.check_nodes(str(url)))
self.emit(QtCore.SIGNAL('updated_projects'), OverallIntegrationStatus(overall_status))
def run(self):
self.process()
def check_nodes(self, url):
return FilteredContinuousIntegrationServer(ProjectLoader(url, self.config.timeout).get_data(), self.config.get_project_excludes(url))
class ProjectLoader:
def __init__(self, url, timeout):
self.url = url
self.timeout = timeout
def get_data(self):
print "checking %s" % self.url
try:
data = HttpConnection().connect(self.url, self.timeout)
except Exception, e:
print e
return ContinuousIntegrationServer(self.url, [], True)
dom = minidom.parse(data)
print "processed %s" % self.url
projects = []
for node in dom.getElementsByTagName('Project'):
projects.append(Project(
{'name': node.getAttribute('name'), 'lastBuildStatus': node.getAttribute('lastBuildStatus'), 'activity': node.getAttribute('activity'), 'url': node.getAttribute('webUrl'),
'lastBuildTime': node.getAttribute('lastBuildTime'), 'server_url': self.url})) # WRONG
return ContinuousIntegrationServer(self.url, projects)
BuildNotify-0.3.5/buildnotifylib/core/http_connection.py 0000644 0001750 0001750 00000001672 12315063423 023375 0 ustar anay anay 0000000 0000000 import socket
import urllib2
import urlparse
import base64
import platform
class HttpConnection:
def __init__(self):
self.user_agent = "%s-%s" % ("BuildNotify", platform.platform())
def connect(self, url, timeout):
socket.setdefaulttimeout(timeout)
urlparts = urlparse.urlparse(url)
username, password = urlparts.username, urlparts.password
replace_string = "%s:%s@" % (username, password)
host = urlparts.netloc.replace(replace_string, "")
url_without_auth = urlparse.urlunparse((urlparts.scheme, host, urlparts.path, urlparts.params, urlparts.query, urlparts.fragment))
headers = {'User-Agent': self.user_agent}
if username is not None:
encodedstring = base64.encodestring("%s:%s" % (username, password))[:-1]
headers["Authorization"] = "Basic %s" % encodedstring
return urllib2.urlopen(urllib2.Request(url_without_auth, None, headers))
BuildNotify-0.3.5/buildnotifylib/core/distance_of_time.py 0000644 0001750 0001750 00000002535 12315063423 023472 0 ustar anay anay 0000000 0000000 from datetime import datetime
import pytz
class DistanceOfTime:
def __init__(self, from_date, timezone):
self.from_date = from_date
self.timezone = timezone
def age(self):
since_date = datetime.now(tz=pytz.timezone(self.timezone)).replace(tzinfo=None)
distance_in_time = since_date - self.from_date
distance_in_seconds = int(round(abs(distance_in_time.days * 86400 + distance_in_time.seconds)))
distance_in_minutes = int(round(distance_in_seconds / 60))
if distance_in_minutes <= 1:
return "1 minute"
elif distance_in_minutes < 45:
return "%s minutes" % distance_in_minutes
elif distance_in_minutes < 90:
return "1 hour"
elif distance_in_minutes < 1440:
return "%d hours" % (round(distance_in_minutes / 60.0))
elif distance_in_minutes < 2880:
return "1 day"
elif distance_in_minutes < 43220:
return "%d days" % (round(distance_in_minutes / 1440))
elif distance_in_minutes < 86400:
return "1 month"
elif distance_in_minutes < 525600:
return "%d months" % (round(distance_in_minutes / 43200))
elif distance_in_minutes < 1051200:
return "1 year"
else:
return "over %d years" % (round(distance_in_minutes / 525600))
BuildNotify-0.3.5/buildnotifylib/core/__init__.py 0000644 0001750 0001750 00000000024 12315063423 021724 0 ustar anay anay 0000000 0000000 __author__ = 'anay'
BuildNotify-0.3.5/buildnotifylib/core/timed_event.py 0000644 0001750 0001750 00000002530 12315063423 022474 0 ustar anay anay 0000000 0000000 from PyQt4 import QtCore
from PyQt4.QtCore import QThread
class TimedEvent:
def __init__(self, parent, event_target, interval=2000):
self.event_target = event_target
self.parent = parent
self.interval = interval
def start(self):
self.timer = QtCore.QTimer()
self.parent.connect(self.timer, QtCore.SIGNAL('timeout()'), self.event_target)
self.timer.setInterval(self.interval)
self.timer.setSingleShot(True)
self.timer.start()
def set_interval(self, interval):
self.interval = interval
class RepeatTimedEvent:
def __init__(self, parent, event_target, repeat_count):
self.parent = parent
self.repeat_count = repeat_count
self.event_target = event_target
self.event_happened_count = 0
def start(self):
self.timed_event = TimedEvent(self.parent, self.on_event)
self.timed_event.start()
def on_event(self):
self.event_target(self.event_happened_count)
self.event_happened_count += 1
if self.event_happened_count != self.repeat_count:
self.start()
class BackgroundEvent(QThread):
def __init__(self, task, parent=None):
QThread.__init__(self, parent)
self.task = task
def run(self):
data = self.task()
self.emit(QtCore.SIGNAL('complete'), data)
BuildNotify-0.3.5/buildnotifylib/build_icons.py 0000644 0001750 0001750 00000003037 12315063423 021536 0 ustar anay anay 0000000 0000000 from PyQt4 import QtGui, QtCore
class BuildIcons:
success_sleeping = 'buildnotify-success'
success_building = 'buildnotify-success-building'
failure_sleeping = 'buildnotify-failure'
failure_building = 'buildnotify-failure-building'
unavailable = 'buildnotify-inactive'
resource_path = ":/status/icons/%s.svg"
theme_resource_path = "%s"
def __init__(self):
self.all_status = {'Success.Sleeping': self.success_sleeping, 'Success.CheckingModifications': self.success_sleeping, 'Success.Building': self.success_building,
'Failure.Sleeping': self.failure_sleeping, 'Failure.CheckingModifications': self.failure_sleeping, 'Failure.Building': self.failure_building,
'unavailable': self.unavailable}
def for_status(self, status):
return QtGui.QIcon.fromTheme(self.get_path(self.theme_resource_path, status), QtGui.QIcon(self.get_path(self.resource_path, status)))
def for_aggregate_status(self, status, count):
if count is "0":
return self.for_status(status)
icon = self.for_status(status)
pixmap = icon.pixmap(22, 22)
painter = QtGui.QPainter(pixmap)
painter.setOpacity(1)
painter.drawText(pixmap.rect(), QtCore.Qt.AlignCenter, count)
painter.end()
return QtGui.QIcon(pixmap)
def get_path(self, resource_path, status):
if status in self.all_status:
return resource_path % self.all_status[status]
return resource_path % self.all_status['unavailable']
BuildNotify-0.3.5/buildnotifylib/server_configuration_dialog.py 0000644 0001750 0001750 00000005302 12315063423 025015 0 ustar anay anay 0000000 0000000 import pytz
from PyQt4 import QtCore
from PyQt4.QtCore import Qt
from PyQt4 import QtGui
from buildnotifylib.generated.server_configuration_ui import Ui_serverConfigurationDialog
from buildnotifylib.core.timed_event import BackgroundEvent
from buildnotifylib.core.projects import ProjectLoader
class ServerConfigurationDialog(QtGui.QDialog):
def __init__(self, editable, url, conf, parent=None):
QtGui.QDialog.__init__(self, parent)
self.ui = Ui_serverConfigurationDialog()
self.ui.setupUi(self)
self.editable = editable
self.ui.addServerUrl.setText(url)
self.conf = conf
timezones = QtCore.QStringList(pytz.all_timezones)
self.ui.timezoneList.addItems(timezones)
self.ui.timezoneList.setCurrentIndex(timezones.indexOf(self.conf.get_timezone(self.server_url())))
if not editable:
self.auto_load()
self.connect(self.ui.loadUrlButton, QtCore.SIGNAL("clicked()"), self.fetch_data)
def auto_load(self):
self.ui.addServerUrl.setReadOnly(True)
self.ui.loadUrlButton.setEnabled(False)
self.fetch_data()
def fetch_data(self):
self.ui.loadUrlButton.setEnabled(False)
self.event = BackgroundEvent(self.load_projects, self)
self.connect(self.event, QtCore.SIGNAL('complete'), lambda data: self.load_data(data))
self.event.start()
def load_projects(self):
self.project_loader = ProjectLoader(self.server_url(), self.conf.timeout)
return self.project_loader.get_data()
def load_data(self, server):
self.ui.loadUrlButton.setEnabled(self.editable)
excluded_projects = self.conf.get_project_excludes(self.server_url())
projects_model = QtGui.QStandardItemModel()
for project in server.projects:
item = QtGui.QStandardItem(project.name)
item.setCheckable(True)
check = Qt.Unchecked if project.name in excluded_projects else Qt.Checked
item.setCheckState(check)
projects_model.appendRow(item)
self.ui.projectsList.setModel(projects_model)
def server_url(self):
return str(self.ui.addServerUrl.text())
def save(self):
projects_model = self.ui.projectsList.model()
if projects_model is None:
return self.server_url()
excluded_projects = [str(projects_model.index(index, 0).data().toString()) for index in range(projects_model.rowCount()) if projects_model.index(index, 0).data(Qt.CheckStateRole) == Qt.Unchecked]
self.conf.set_project_excludes(self.server_url(), excluded_projects)
self.conf.set_project_timezone(self.server_url(), self.ui.timezoneList.currentText())
return self.server_url()
BuildNotify-0.3.5/buildnotifylib/buildnotify.py 0000644 0001750 0001750 00000004400 12315063423 021567 0 ustar anay anay 0000000 0000000 import sys
from app_ui import AppUi
from app_notification import AppNotification
from config import Config
from buildnotifylib.core.projects import ProjectsPopulator
from PyQt4 import QtGui, QtCore
from build_icons import BuildIcons
from buildnotifylib.core.timed_event import TimedEvent, RepeatTimedEvent
class BuildNotify:
def __init__(self):
self.conf = Config()
self.app = QtGui.QApplication(sys.argv)
self.build_icons = BuildIcons()
self.app.setWindowIcon(self.build_icons.for_status("Success.Sleeping"))
self.app.setQuitOnLastWindowClosed(False)
self.ready = False
self.timed_event = RepeatTimedEvent(self.app, self.delayed_start, 5)
self.timed_event.start()
sys.exit(self.app.exec_())
def delayed_start(self, event_count):
if not QtGui.QSystemTrayIcon.isSystemTrayAvailable():
if event_count == 5:
QtGui.QMessageBox.critical(None, "BuildNotify", "I couldn't detect any system tray on this system.")
sys.exit(1)
self.timed_event.start()
if not self.ready:
self.ready = True
self.run_app()
def run_app(self):
self.projects_populator = ProjectsPopulator(self.conf, self.app)
self.app.connect(self.projects_populator, QtCore.SIGNAL('updated_projects'), self.update_projects)
self.app.connect(self.app, QtCore.SIGNAL('reload_project_data'), self.reload_project_data)
self.app_ui = AppUi(self.app, self.conf, self.build_icons)
self.app_notification = AppNotification(self.conf, self.app_ui.tray)
self.auto_poll()
def reload_project_data(self):
self.projects_populator.reload()
def update_projects(self, integration_status):
self.app_notification.update_projects(integration_status)
self.app_ui.update_projects(integration_status)
def auto_poll(self):
self.timed_event = TimedEvent(self.app, self.check_nodes)
self.timed_event.set_interval(1000)
self.timed_event.start()
def check_nodes(self):
self.projects_populator.load_from_server()
self.timed_event.set_interval(self.conf.get_interval_in_millis())
self.timed_event.start()
if __name__ == '__main__':
BuildNotify()
BuildNotify-0.3.5/buildnotifylib/project_status_notification.py 0000644 0001750 0001750 00000010743 12315063423 025065 0 ustar anay anay 0000000 0000000 from datetime import datetime
import subprocess
class ProjectStatusNotification:
def __init__(self, config, old_integration_status, current_integration_status, notification):
self.config = config
self.old_integration_status = old_integration_status
self.current_integration_status = current_integration_status
self.notification = notification
self.timed_project_filter = TimedProjectFilter()
def show_notifications(self):
project_status = ProjectStatus(self.old_integration_status.get_projects(), self.current_integration_status.get_projects())
self.show_notification_msg(self.config.get_value("fixedBuild"), project_status.successful_builds(), "Fixed builds")
self.show_notification_msg(self.config.get_value("brokenBuild"), project_status.failing_builds(), "Broken builds")
self.show_notification_msg(self.config.get_value("stillFailingBuild"), project_status.still_failing_builds(), "Build is still failing")
if self.current_integration_status.unavailable_servers() is not []:
self.show_notification_msg(self.config.get_value("connectivityIssues"),
self.timed_project_filter.filter(map(lambda server: server.url, self.current_integration_status.unavailable_servers())), "Connectivity issues")
self.show_notification_msg(self.config.get_value("successfulBuild"), project_status.still_successful_builds(), "Yet another successful build")
def show_notification_msg(self, show_notification, builds, message):
if show_notification is False or builds == []:
return
self.notification.show_message(message, "\n".join(builds))
if self.config.get_custom_script_enabled():
command = self.config.get_custom_script().replace('#status#', message).replace('#projects#', ",".join(builds))
subprocess.Popen(command, shell=True)
class TimedProjectFilter:
map = dict()
fact = [1, 2, 3, 5, 8, 13, 21]
def __init__(self):
pass
def filter(self, urls):
return filter(lambda url: self.is_new(url), urls)
def is_new(self, url):
if url not in self.map:
self.map[url] = (datetime.now(), 1)
return True
connection_time, fail_count = self.map[url]
fail_count += 1
if self.fact[len(self.fact) - 1] <= fail_count:
fail_count = 1
self.map[url] = (connection_time, fail_count)
return fail_count in self.fact
class ProjectStatus:
def __init__(self, old_projects, current_projects):
self.old_projects = old_projects
self.current_projects = current_projects
def failing_builds(self):
return self.filter_all(lambda project_tuple: project_tuple.has_failed())
def successful_builds(self):
return self.filter_all(lambda project_tuple: project_tuple.has_succeeded())
def still_failing_builds(self):
return self.filter_all(lambda project_tuple: project_tuple.has_been_failing())
def still_successful_builds(self):
return self.filter_all(lambda project_tuple: project_tuple.has_been_successful())
def filter_all(self, filter_fn):
project_tuples = map(lambda current_project: self.tuple_for(current_project), self.current_projects)
project_tuples = filter(filter_fn, project_tuples)
return map(lambda project_tuple: project_tuple.current_project.name, project_tuples)
def tuple_for(self, new_project):
for project in self.old_projects:
if project.name == new_project.name:
return ProjectTuple(new_project, project)
return ProjectTuple(new_project, None)
class ProjectTuple:
def __init__(self, current_project, old_project):
self.current_project = current_project
self.old_project = old_project
def has_failed(self):
return self.status('Failure', 'Success')
def has_succeeded(self):
return self.status('Success', 'Failure')
def has_been_successful(self):
return (self.old_project is None) or (self.status('Success', 'Success') and self.different_builds())
def has_been_failing(self):
return self.status('Failure', 'Failure') and self.different_builds()
def status(self, new_status, old_status):
return self.current_project.status == new_status and self.old_project is not None and self.old_project.status == old_status
def different_builds(self):
return self.current_project.last_build_time != self.old_project.last_build_time
BuildNotify-0.3.5/buildnotifylib/__init__.py 0000644 0001750 0001750 00000000044 12315063423 020776 0 ustar anay anay 0000000 0000000 from buildnotify import BuildNotify
BuildNotify-0.3.5/buildnotifylib/notifications.py 0000644 0001750 0001750 00000001251 12315063423 022111 0 ustar anay anay 0000000 0000000 try:
import pynotify
except ImportError:
pass
from PyQt4 import QtGui
class Notification:
def __init__(self, widget):
self.widget = widget
self.notification = None
try:
if pynotify.init(" buildnotify "):
self.notification = pynotify.Notification("buildnotify", "buildnotify", None)
except NameError:
pass
def show_message(self, title, text):
if self.notification:
self.notification.update(title, text, None)
if self.notification is None or not self.notification.show():
self.widget.showMessage(title, text, QtGui.QSystemTrayIcon.Information, 3000)
BuildNotify-0.3.5/buildnotifylib/app_ui.py 0000644 0001750 0001750 00000001464 12315063423 020523 0 ustar anay anay 0000000 0000000 from PyQt4 import QtGui
from time import strftime
from app_menu import AppMenu
class AppUi:
def __init__(self, app, conf, build_icons):
self.widget = QtGui.QWidget()
self.app = app
self.build_icons = build_icons
self.tray = QtGui.QSystemTrayIcon(self.build_icons.for_status(None), self.widget)
self.tray.show()
self.app_menu = AppMenu(self.app, self.tray, self.widget, conf, self.build_icons);
def update_projects(self, integration_status):
count = str(len(integration_status.get_failing_builds()))
self.tray.setIcon(self.build_icons.for_aggregate_status(integration_status.get_build_status(), count))
self.app_menu.update(integration_status.get_projects())
self.tray.setToolTip("Last checked: " + strftime("%Y-%m-%d %H:%M:%S"))
BuildNotify-0.3.5/buildnotifylib/app_notification.py 0000644 0001750 0001750 00000001114 12315063423 022564 0 ustar anay anay 0000000 0000000 from project_status_notification import ProjectStatusNotification
from notifications import Notification
class AppNotification:
def __init__(self, config, widget):
self.config = config
self.notification = Notification(widget)
self.integration_status = None
def update_projects(self, new_integration_status):
if self.integration_status is not None:
ProjectStatusNotification(self.config, self.integration_status, new_integration_status, self.notification).show_notifications()
self.integration_status = new_integration_status
BuildNotify-0.3.5/buildnotifylib/version.py 0000644 0001750 0001750 00000000023 12315063423 020721 0 ustar anay anay 0000000 0000000 VERSION = "0.3.5"
BuildNotify-0.3.5/buildnotifylib/app_menu.py 0000644 0001750 0001750 00000005162 12315063423 021051 0 ustar anay anay 0000000 0000000 import sys
import webbrowser
from PyQt4 import QtGui
from PyQt4 import QtCore
from buildnotifylib.core.distance_of_time import DistanceOfTime
from preferences import PreferencesDialog
from version import VERSION
class AppMenu:
def __init__(self, app, tray, widget, conf, build_icons):
self.menu = QtGui.QMenu(widget)
tray.setContextMenu(self.menu)
self.conf = conf
self.app = app
self.build_icons = build_icons
self.create_default_menu_items()
def update(self, projects):
projects.sort(lambda x, y: (x.last_build_time - y.last_build_time).days)
self.menu.clear()
for project in projects:
self.create_menu_item(project.name, self.build_icons.for_status(project.get_build_status()), project.url, project.last_build_time, project.server_url)
self.create_default_menu_items()
def create_default_menu_items(self):
self.menu.addSeparator()
self.menu.addAction(QtGui.QAction("About", self.menu, triggered=self.about_clicked))
self.menu.addAction(QtGui.QAction("Preferences", self.menu, triggered=self.preferences_clicked))
self.menu.addAction(QtGui.QAction("Exit", self.menu, triggered=self.exit))
def about_clicked(self, widget):
QtGui.QMessageBox.about(self.menu, "About BuildNotify %s" % VERSION,
"BuildNotify %s has been developed using PyQt4 and serves as a build notification tool for cruise control. In case of any suggestions/bugs," % VERSION +
"please visit http://bitbucket.org/Anay/buildnotify and provide your feedback.")
def preferences_clicked(self, widget):
self.preferences_dialog = PreferencesDialog(self.conf, self.menu)
if self.preferences_dialog.exec_() == QtGui.QDialog.Accepted:
self.preferences_dialog.save()
self.app.emit(QtCore.SIGNAL('reload_project_data'))
def exit(self, widget):
sys.exit()
def create_menu_item(self, label, icon, url, last_build_time, server_url):
menu_item_label = label
if self.conf.get_value("lastBuildTimeForProject"):
menu_item_label = label + ", " + DistanceOfTime(last_build_time, self.conf.get_project_timezone(url, server_url)).age() + " ago"
action = self.menu.addAction(icon, menu_item_label)
action.setIconVisibleInMenu(True)
receiver = lambda url=url: self.open_url(self, url)
QtCore.QObject.connect(action, QtCore.SIGNAL('triggered()'), receiver)
def open_url(self, something, url):
webbrowser.open(url)
BuildNotify-0.3.5/README 0000755 0001750 0001750 00000000543 12315063423 014535 0 ustar anay anay 0000000 0000000 INSTALL:
a) Execute buildnotifyapplet.py from the current directory to start buildnotify.
b) Alternatively you can install using easy_install.
b.1) Run easy_install BuildNotify
b.2) Run /usr/bin/buildnotifyapplet.py or c:/python2.6/scripts/buildnotifyapplet.py to launch it.
DEPENDENCIES
Install pyqt4, pytz and python-dateutil.
BuildNotify-0.3.5/MANIFEST.in 0000644 0001750 0001750 00000000046 12315063423 015406 0 ustar anay anay 0000000 0000000 recursive-include buildnotifylib *.py