-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuilder.py
137 lines (113 loc) · 4.11 KB
/
builder.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
import sys
import json
from os import environ
from os.path import join
from twisted.internet import defer, reactor
from twisted.internet.protocol import ProcessProtocol
from twisted.internet.error import ProcessTerminated, ProcessExitedAlready, ProcessDone
from autobahn.twisted.component import run, Component
from autobahn.wamp.types import SubscribeOptions
from autobahn.wamp.cryptobox import KeyRing, Key
# Storing our secrets in files to make the examples simpler; something
# like 'keyring' or 'vault' would be preferable
keyring = KeyRing()
with open('secrets-builder-authkey', 'rb') as f:
builder_auth_key = f.read()
with open('secrets-paths', 'rb') as f:
basedir = f.read().strip().decode('ascii')
with open('secrets-builder-priv', 'rb') as priv:
with open('secrets-webhook-pub', 'rb') as pub:
# we are *receiving* events, so we're the responder
key = Key(
responder_priv=priv.read().decode('ascii'), # webhook will encrypt to this
originator_pub=pub.read().decode('ascii'), # if we have to reply, encrypt to this
)
keyring.set_key(u'webhook.github.push', key)
# configure our component, connecting via a Unix socket locally and
# authenticating with 'cryptosign'
builder = Component(
transports=[
{
u"url": u"ws://localhost/ws",
u"endpoint": {
"type": "unix",
"path": "./.crossbar/sock"
}
}
],
authentication={
"cryptosign": {
u"authid": u"builder",
u"authrole": u"agent",
u"privkey": builder_auth_key,
}
},
realm=u"agent",
)
class _Task(ProcessProtocol):
def __init__(self, all_done, launched, stdout=None, stderr=None):
self._stderr = stderr
self._stdout = stdout
self._all_done = all_done
self._launched = launched
# some cutesy IProcessProtocol overrides
if self._stderr is not None:
self.outReceived = self._stderr.write
if self._stdout is not None:
self.errReceived = self._stdout.write
def processEnded(self, reason):
"""IProcessProtocol API"""
fail = reason.value
is_fine = isinstance(fail, (ProcessDone, ProcessTerminated)) and \
fail.exitCode == 0
for d in [self._launched, self._all_done]:
if not d.called:
if is_fine:
d.callback(None)
else:
d.errback(fail)
@defer.inlineCallbacks
def _run(reactor, run_dir, program, *args):
done = defer.Deferred()
launched = defer.Deferred()
proto = _Task(
done, launched,
# stdout=sys.stdout,
stderr=sys.stderr,
)
print("running: {} {}".format(program, ' '.join(args)))
transport = reactor.spawnProcess(
proto, program,
args=(program, ) + args,
env=environ,
path=run_dir,
)
yield done
@builder.subscribe(u'webhook.github.push')
@defer.inlineCallbacks
def _github_push(**kw):
print("github push: {}".format(kw['ref']))
print(" commits added:")
for commit in kw['commits']:
print(" {id}: {message}".format(**commit))
if kw['ref'] != 'refs/heads/master':
print(" not master; ignoring")
return
print("Rebuilding.")
path = "{}/venv/bin:{}".format(basedir, environ.get('PATH', ''))
environ['PATH'] = path
from twisted.internet import reactor
yield _run(reactor, join(basedir, u'git'), u'/usr/bin/git', u'pull')
yield _run(reactor, join(basedir, u'git', u'docs'), '/usr/bin/make', 'html')
print("github push processed successfully")
@builder.subscribe(u'webhook.github.', options=SubscribeOptions(match=u"prefix", details_arg="_details"))
def _github_notify(**kw):
details = kw.pop("_details")
print("{}: {} {}".format(details.topic, kw.get('created_at', ''), kw.get('state', '')))
# print(kw.keys())
@builder.on_join
def joined(session, details):
print("builder joined: {} {}".format(session, details))
session.set_payload_codec(keyring) # e2e encryption keys
if __name__ == '__main__':
run([builder])