Skip to content

Commit

Permalink
use a more standard way to report
Browse files Browse the repository at this point in the history
  • Loading branch information
EmilioPeJu committed Jun 23, 2017
1 parent e48d4da commit 2af0562
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 84 deletions.
135 changes: 81 additions & 54 deletions master/buildbot/reporters/bitbucketserver.py
Expand Up @@ -18,6 +18,7 @@
from future.moves.urllib.parse import urlparse

from twisted.internet import defer
from twisted.python import log

from buildbot.process.properties import Interpolate
from buildbot.process.properties import Properties
Expand All @@ -27,9 +28,8 @@
from buildbot.util import bytes2NativeString
from buildbot.util import httpclientservice
from buildbot.util import unicode2bytes
from buildbot.util.logger import Logger
from buildbot.util import unicode2NativeString

log = Logger()

# Magic words understood by Bitbucket Server REST API
INPROGRESS = 'INPROGRESS'
Expand All @@ -51,60 +51,80 @@ def reconfigService(self, base_url, user, password, key=None,
yield http.HttpStatusPushBase.reconfigService(
self, wantProperties=True, **kwargs)
self.key = key or Interpolate('%(prop:buildername)s')
self.statusName = statusName
self.context = statusName
self.endDescription = endDescription or 'Build done.'
self.startDescription = startDescription or 'Build started.'
self.verbose = verbose
self._http = yield httpclientservice.HTTPClientService.getService(
self.master, base_url, auth=(user, password),
debug=self.debug, verify=self.verify)

def createStatus(self, sha, state, url, key, description=None, context=None):
payload = {
'state': state,
'url': url,
'key': key,
}

if description:
payload['description'] = description
if context:
payload['name'] = context

return self._http.post(STATUS_API_URL.format(sha=sha), json=payload)

@defer.inlineCallbacks
def send(self, build):
props = Properties.fromDict(build['properties'])
results = build['results']
if build['complete']:
status = SUCCESSFUL if results == SUCCESS else FAILED
state = SUCCESSFUL if results == SUCCESS else FAILED
description = self.endDescription
else:
status = INPROGRESS
state = INPROGRESS
description = self.startDescription

# got_revision could be a string, a dictionary or None
got_revision = props.getProperty('got_revision', None)
for sourcestamp in build['buildset']['sourcestamps']:
sha = sourcestamp['revision']

if sha is None:
if isinstance(got_revision, dict):
sha = got_revision[sourcestamp['codebase']]
else:
sha = got_revision

if sha is None:
log.error("Unable to get the commit hash")
continue

key = yield props.render(self.key)
payload = {
'state': status,
'url': build['url'],
'key': key,
}
if description:
payload['description'] = yield props.render(description)
if self.statusName:
payload['name'] = yield props.render(self.statusName)
response = yield self._http.post(
STATUS_API_URL.format(sha=sha), json=payload)
if response.code == HTTP_PROCESSED:
if self.verbose:
log.info('Status "{status}" sent for {sha}.',
status=status, sha=sha)
else:
content = yield response.content()
log.error("{code}: Unable to send Bitbucket Server status: {content}",
code=response.code, content=content)
key = yield props.render(self.key)
description = yield props.render(description) if description else None
context = yield props.render(self.context) if self.context else None

sourcestamps = build['buildset']['sourcestamps']

for sourcestamp in sourcestamps:
try:
sha = unicode2NativeString(sourcestamp['revision'])

if sha is None:
log.msg("Unable to get the commit hash")
continue

key = unicode2NativeString(key)
url = unicode2NativeString(build['url'])

res = yield self.createStatus(
sha=sha,
state=state,
url=url,
key=key,
description=description,
context=context
)

if res.code not in (HTTP_PROCESSED,):
content = yield res.content()
log.msg("{code}: Unable to send Bitbucket Server status: {content}"
.format(code=res.code, content=content))
elif self.verbose:
log.msg('Status "{state}" sent for {sha}.'
.format(state=state, sha=sha))
except Exception as e:
log.err(
e,
'Failed to send status "{state}" for '
'{repo} at {sha}'.format(
state=state,
repo=sourcestamp['repository'], sha=sha
))


class BitbucketServerPRCommentPush(notifier.NotifierBase):
Expand Down Expand Up @@ -143,6 +163,12 @@ def workerMissing(self, key, worker):
# a comment is always associated to a change
pass

def sendComment(self, pr_url, text):
path = urlparse(unicode2bytes(pr_url)).path
payload = {'text': text}
return self._http.post(COMMENT_API_URL.format(
path=bytes2NativeString(path)), json=payload)

@defer.inlineCallbacks
def sendMessage(self, body, subject=None, type=None, builderName=None,
results=None, builds=None, users=None, patches=None,
Expand All @@ -152,17 +178,18 @@ def sendMessage(self, body, subject=None, type=None, builderName=None,
props = Properties.fromDict(build['properties'])
pr_urls.add(props.getProperty("pullrequesturl"))
for pr_url in pr_urls:
# we assume that the PR URL is well-formed as it comes from a PR event
path = urlparse(unicode2bytes(pr_url)).path
payload = {'text': body}
response = yield self._http.post(
COMMENT_API_URL.format(
path=bytes2NativeString(path)), json=payload)

if response.code == HTTP_CREATED:
if self.verbose:
log.info('Comment sent to {url}', url=pr_url)
else:
content = yield response.content()
log.error("{code}: Unable to send a comment: {content}",
code=response.code, content=content)
try:
res = yield self.sendComment(
pr_url=pr_url,
text=body
)
if res.code not in (HTTP_CREATED,):
content = yield res.content()
log.msg("{code}: Unable to send a comment: {content}"
.format(code=res.code, content=content))
elif self.verbose:
log.msg('Comment sent to {url}'.format(url=pr_url))
except Exception as e:
log.err(
e,
'Failed to send a comment to "{}"'.format(pr_url))
37 changes: 7 additions & 30 deletions master/buildbot/test/unit/test_reporter_bitbucketserver.py
Expand Up @@ -165,38 +165,15 @@ def test_basic_with_no_revision(self):
build = yield self.setupBuildResults(SUCCESS)
finally:
self.TEST_REVISION = old_test_revision
self._check_start_and_finish_build(build)

@defer.inlineCallbacks
def test_basic_with_no_revision_and_dict_got_revision(self):
yield self.setupReporter()
old_test_revision = self.TEST_REVISION
old_got_revision = self.TEST_PROPS['got_revision']
try:
self.TEST_REVISION = None
self.TEST_PROPS['got_revision'] = {'cbgerrit': 'd34db33fd43db33f'}
build = yield self.setupBuildResults(SUCCESS)
finally:
self.TEST_REVISION = old_test_revision
self.TEST_PROPS['got_revision'] = old_got_revision
self._check_start_and_finish_build(build)

@defer.inlineCallbacks
def test_basic_with_no_revision_and_no_got_revision(self):
yield self.setupReporter()
old_test_revision = self.TEST_REVISION
old_got_revision = self.TEST_PROPS['got_revision']
try:
self.TEST_REVISION = None
self.TEST_PROPS['got_revision'] = None
build = yield self.setupBuildResults(SUCCESS)
finally:
self.TEST_REVISION = old_test_revision
self.TEST_PROPS['got_revision'] = old_got_revision

self.setUpLogging()
# we don't expect any request
build['complete'] = False
self.sp.buildStarted(("build", 20, "started"), build)
self.assertLogged('Unable to get the commit hash')
self.assertLogged("Unable to get the commit hash")
build['complete'] = True
self.sp.buildFinished(("build", 20, "finished"), build)
build['results'] = FAILURE
self.sp.buildFinished(("build", 20, "finished"), build)


UNICODE_BODY = u"body: \u00E5\u00E4\u00F6 text"
Expand Down

0 comments on commit 2af0562

Please sign in to comment.