forked from StackStorm-Exchange/stackstorm-github
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgithub_repository_sensor.py
174 lines (134 loc) · 5.85 KB
/
github_repository_sensor.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import six
import eventlet
from github import Github
from st2reactor.sensor.base import PollingSensor
eventlet.monkey_patch(
os=True,
select=True,
socket=True,
thread=True,
time=True)
DATE_FORMAT_STRING = '%Y-%m-%d %H:%M:%S'
# Default Github API url
DEFAULT_API_URL = 'https://api.github.com'
class GithubRepositorySensor(PollingSensor):
def __init__(self, sensor_service, config=None, poll_interval=None):
super(GithubRepositorySensor, self).__init__(sensor_service=sensor_service,
config=config,
poll_interval=poll_interval)
self._trigger_ref = 'github.repository_event'
self._logger = self._sensor_service.get_logger(__name__)
self._client = None
self._repositories = []
self._last_event_ids = {}
self.EVENT_TYPE_WHITELIST = []
def setup(self):
# Empty string '' is not ok but None is fine. (Sigh)
github_type = self._config.get('github_type', None)
if github_type == 'online':
config_base_url = DEFAULT_API_URL
else:
config_base_url = self._config.get('base_url', None) or None
config_token = self._config.get('token', None) or None
self._client = Github(config_token or None, base_url=config_base_url)
repository_sensor = self._config.get('repository_sensor', None)
if repository_sensor is None:
raise ValueError('"repository_sensor" config value is required.')
self.EVENT_TYPE_WHITELIST = repository_sensor.get('event_type_whitelist', [])
repositories = repository_sensor.get('repositories', None)
if not repositories:
raise ValueError('GithubRepositorySensor should have at least 1 repository.')
for repository_dict in repositories:
user = self._client.get_user(repository_dict['user'])
repository = user.get_repo(repository_dict['name'])
self._repositories.append((repository_dict['name'], repository))
def poll(self):
for repository_name, repository_obj in self._repositories:
self._logger.debug('Processing repository "%s"' %
(repository_name))
self._process_repository(name=repository_name,
repository=repository_obj)
def _process_repository(self, name, repository):
"""
Retrieve events for the provided repository and dispatch triggers for
new events.
:param name: Repository name.
:type name: ``str``
:param repository: Repository object.
:type repository: :class:`Repository`
"""
assert(isinstance(name, six.text_type))
# Assume a default value of 30. Better for the sensor to operate with some
# default value in this case rather than raise an exception.
count = self._config['repository_sensor'].get('count', 30)
repository_events = repository.get_events()
events = list(repository_events[:count]) \
if repository_events.totalCount > count else list(repository_events)
events.sort(key=lambda _event: _event.id, reverse=False)
last_event_id = self._get_last_id(name=name)
for event in events:
if last_event_id and int(event.id) <= int(last_event_id):
# This event has already been processed
continue
self._handle_event(repository=name, event=event)
if events:
self._set_last_id(name=name, last_id=events[-1].id)
def cleanup(self):
pass
def add_trigger(self, trigger):
pass
def update_trigger(self, trigger):
pass
def remove_trigger(self, trigger):
pass
def _get_last_id(self, name):
"""
:param name: Repository name.
:type name: ``str``
"""
if not self._last_event_ids.get(name, None) and hasattr(self._sensor_service, 'get_value'):
key_name = 'last_id.%s' % (name)
self._last_event_ids[name] = self._sensor_service.get_value(name=key_name)
return self._last_event_ids.get(name, None)
def _set_last_id(self, name, last_id):
"""
:param name: Repository name.
:type name: ``str``
"""
self._last_event_ids[name] = last_id
if hasattr(self._sensor_service, 'set_value'):
key_name = 'last_id.%s' % (name)
self._sensor_service.set_value(name=key_name, value=last_id)
def _handle_event(self, repository, event):
if event.type not in self.EVENT_TYPE_WHITELIST:
self._logger.debug('Skipping ignored event (type=%s)' % (event.type))
return
self._dispatch_trigger_for_event(repository=repository, event=event)
def _dispatch_trigger_for_event(self, repository, event):
trigger = self._trigger_ref
created_at = event.created_at
if created_at:
created_at = created_at.strftime(DATE_FORMAT_STRING)
# Common attributes
payload = {
'repository': repository,
'id': event.id,
'created_at': created_at,
'type': event.type,
'actor': {
'id': event.actor.id,
'login': event.actor.login,
'name': event.actor.name,
'email': event.actor.email,
'loaction': event.actor.location,
'bio': event.actor.bio,
'url': event.actor.html_url
},
'payload': {}
}
event_specific_payload = self._get_payload_for_event(event=event)
payload['payload'] = event_specific_payload
self._sensor_service.dispatch(trigger=trigger, payload=payload)
def _get_payload_for_event(self, event):
payload = event.payload or {}
return payload