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
|
# This file is part of Buildbot. Buildbot is free software: you can
# redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, version 2.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright Buildbot Team Members
"""Push events to gerrit
."""
from buildbot.status.base import StatusReceiverMultiService
from buildbot.status.builder import Results, SUCCESS, RETRY
from twisted.internet import reactor
from twisted.internet.protocol import ProcessProtocol
def defaultReviewCB(builderName, build, result, status, arg):
if result == RETRY:
return None, 0, 0
message = "Buildbot finished compiling your patchset\n"
message += "on configuration: %s\n" % builderName
message += "The result is: %s\n" % Results[result].upper()
# message, verified, reviewed
return message, (result == SUCCESS or -1), 0
class GerritStatusPush(StatusReceiverMultiService):
"""Event streamer to a gerrit ssh server."""
def __init__(self, server, username, reviewCB=defaultReviewCB,
startCB=None, port=29418, reviewArg=None,
startArg=None, **kwargs):
"""
@param server: Gerrit SSH server's address to use for push event notifications.
@param username: Gerrit SSH server's username.
@param reviewCB: Callback that is called each time a build is finished, and that is used
to define the message and review approvals depending on the build result.
@param startCB: Callback that is called each time a build is started.
Used to define the message sent to Gerrit.
@param port: Gerrit SSH server's port.
@param reviewArg: Optional argument passed to the review callback.
@param startArg: Optional argument passed to the start callback.
"""
StatusReceiverMultiService.__init__(self)
# Parameters.
self.gerrit_server = server
self.gerrit_username = username
self.gerrit_port = port
self.reviewCB = reviewCB
self.reviewArg = reviewArg
self.startCB = startCB
self.startArg = startArg
class LocalPP(ProcessProtocol):
def __init__(self, status):
self.status = status
def outReceived(self, data):
print "gerritout:", data
def errReceived(self, data):
print "gerriterr:", data
def processEnded(self, status_object):
if status_object.value.exitCode:
print "gerrit status: ERROR:", status_object
else:
print "gerrit status: OK"
def startService(self):
print """Starting up."""
StatusReceiverMultiService.startService(self)
self.status = self.parent.getStatus()
self.status.subscribe(self)
def builderAdded(self, name, builder):
return self # subscribe to this builder
def buildStarted(self, builderName, build):
if self.startCB is not None:
message = self.startCB(builderName, build, self.startArg)
self.sendCodeReviews(build, message)
def buildFinished(self, builderName, build, result):
"""Do the SSH gerrit verify command to the server."""
message, verified, reviewed = self.reviewCB(builderName, build, result, self.status, self.reviewArg)
self.sendCodeReviews(build, message, verified, reviewed)
def sendCodeReviews(self, build, message, verified=0, reviewed=0):
if message is None:
return
# Gerrit + Repo
downloads = build.getProperty("repo_downloads")
downloaded = build.getProperty("repo_downloaded")
if downloads is not None and downloaded is not None:
downloaded = downloaded.split(" ")
if downloads and 2 * len(downloads) == len(downloaded):
for i in range(0, len(downloads)):
try:
project, change1 = downloads[i].split(" ")
except ValueError:
return # something is wrong, abort
change2 = downloaded[2 * i]
revision = downloaded[2 * i + 1]
if change1 == change2:
self.sendCodeReview(project, revision, message, verified, reviewed)
else:
return # something is wrong, abort
return
# Gerrit + Git
if build.getProperty("gerrit_branch") is not None: # used only to verify Gerrit source
project = build.getProperty("project")
revision = build.getProperty("got_revision")
# review doesn't really work with multiple revisions, so let's
# just assume it's None there
if isinstance(revision, dict):
revision = None
if project is not None and revision is not None:
self.sendCodeReview(project, revision, message, verified, reviewed)
return
def sendCodeReview(self, project, revision, message=None, verified=0, reviewed=0):
command = ["ssh", self.gerrit_username + "@" + self.gerrit_server, "-p %d" % self.gerrit_port,
"gerrit", "review", "--project %s" % str(project)]
if message:
command.append("--message '%s'" % message.replace("'","\""))
if verified:
command.extend(["--verified %d" % int(verified)])
if reviewed:
command.extend(["--code-review %d" % int(reviewed)])
command.append(str(revision))
print command
reactor.spawnProcess(self.LocalPP(self), "ssh", command)
# vim: set ts=4 sts=4 sw=4 et:
|