Added GiteaStatusPush reporter
This commit is contained in:
parent
29750bcbdb
commit
78ccfc074b
166
buildbot_gitea/reporter.py
Normal file
166
buildbot_gitea/reporter.py
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
# Based on the gitlab reporter from buildbot
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
from twisted.internet import defer
|
||||||
|
from twisted.python import log
|
||||||
|
|
||||||
|
from buildbot.process.properties import Interpolate
|
||||||
|
from buildbot.process.properties import Properties
|
||||||
|
from buildbot.process.results import CANCELLED
|
||||||
|
from buildbot.process.results import EXCEPTION
|
||||||
|
from buildbot.process.results import FAILURE
|
||||||
|
from buildbot.process.results import RETRY
|
||||||
|
from buildbot.process.results import SKIPPED
|
||||||
|
from buildbot.process.results import SUCCESS
|
||||||
|
from buildbot.process.results import WARNINGS
|
||||||
|
from buildbot.reporters import http
|
||||||
|
from buildbot.util import httpclientservice
|
||||||
|
from buildbot.util import unicode2NativeString
|
||||||
|
|
||||||
|
|
||||||
|
class GiteaStatusPush(http.HttpStatusPushBase):
|
||||||
|
name = "GiteaStatusPush"
|
||||||
|
neededDetails = dict(wantProperties=True)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def reconfigService(self, baseURL, token,
|
||||||
|
startDescription=None, endDescription=None,
|
||||||
|
context=None, context_pr=None, verbose=False,
|
||||||
|
warningAsSuccess=False, **kwargs):
|
||||||
|
|
||||||
|
token = yield self.renderSecrets(token)
|
||||||
|
yield http.HttpStatusPushBase.reconfigService(self, **kwargs)
|
||||||
|
|
||||||
|
self.context = context or Interpolate('buildbot/%(prop:buildername)s')
|
||||||
|
self.context_pr = context_pr or \
|
||||||
|
Interpolate('buildbot/pull_request/%(prop:buildername)s')
|
||||||
|
self.startDescription = startDescription or 'Build started.'
|
||||||
|
self.endDescription = endDescription or 'Build done.'
|
||||||
|
if baseURL.endswith('/'):
|
||||||
|
baseURL = baseURL[:-1]
|
||||||
|
self.baseURL = baseURL
|
||||||
|
self._http = yield httpclientservice.HTTPClientService.getService(
|
||||||
|
self.master, baseURL,
|
||||||
|
headers={'AuthorizationHeaderToken': 'token {}'.format(token)},
|
||||||
|
debug=self.debug, verify=self.verify)
|
||||||
|
self.verbose = verbose
|
||||||
|
self.project_ids = {}
|
||||||
|
self.warningAsSuccess = warningAsSuccess
|
||||||
|
|
||||||
|
def createStatus(self,
|
||||||
|
project_owner, repo_name, sha, state, target_url=None,
|
||||||
|
description=None, context=None):
|
||||||
|
"""
|
||||||
|
:param project_owner: username of the owning user or organization
|
||||||
|
:param repo_name: name of the repository
|
||||||
|
:param sha: Full sha to create the status for.
|
||||||
|
:param state: one of the following 'pending', 'success', 'failed'
|
||||||
|
or 'cancelled'.
|
||||||
|
:param target_url: Target url to associate with this status.
|
||||||
|
:param description: Short description of the status.
|
||||||
|
:param context: Context of the result
|
||||||
|
:return: A deferred with the result from GitLab.
|
||||||
|
|
||||||
|
"""
|
||||||
|
payload = {'state': state}
|
||||||
|
|
||||||
|
if description is not None:
|
||||||
|
payload['description'] = description
|
||||||
|
|
||||||
|
if target_url is not None:
|
||||||
|
payload['target_url'] = target_url
|
||||||
|
|
||||||
|
if context is not None:
|
||||||
|
payload['name'] = context
|
||||||
|
|
||||||
|
return self._http.post(
|
||||||
|
'/api/v1/repos/{owner}/{repository}/statuses/{sha}'.format(
|
||||||
|
owner=project_owner,
|
||||||
|
repository=repo_name,
|
||||||
|
sha=sha
|
||||||
|
),
|
||||||
|
json=payload)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def send(self, build):
|
||||||
|
props = Properties.fromDict(build['properties'])
|
||||||
|
props.master = self.master
|
||||||
|
|
||||||
|
if build['complete']:
|
||||||
|
state = {
|
||||||
|
SUCCESS: 'success',
|
||||||
|
WARNINGS: 'success' if self.warningAsSuccess else 'warning',
|
||||||
|
FAILURE: 'failure',
|
||||||
|
SKIPPED: 'success',
|
||||||
|
EXCEPTION: 'error',
|
||||||
|
RETRY: 'pending',
|
||||||
|
CANCELLED: 'error'
|
||||||
|
}.get(build['results'], 'failure')
|
||||||
|
description = yield props.render(self.endDescription)
|
||||||
|
else:
|
||||||
|
state = 'pending'
|
||||||
|
description = yield props.render(self.startDescription)
|
||||||
|
|
||||||
|
if 'pr_id' in props:
|
||||||
|
context = yield props.render(self.context_pr)
|
||||||
|
else:
|
||||||
|
context = yield props.render(self.context)
|
||||||
|
|
||||||
|
sourcestamps = build['buildset']['sourcestamps']
|
||||||
|
|
||||||
|
for sourcestamp in sourcestamps:
|
||||||
|
sha = sourcestamp['revision']
|
||||||
|
if 'repository_name' in props:
|
||||||
|
repository_name = props['repository_name']
|
||||||
|
else:
|
||||||
|
log.msg(
|
||||||
|
"Could not send status, "
|
||||||
|
"build has no repository_name property for Gitea.")
|
||||||
|
continue
|
||||||
|
if 'owner' in props:
|
||||||
|
repository_owner = props['owner']
|
||||||
|
else:
|
||||||
|
log.msg(
|
||||||
|
"Could not send status, "
|
||||||
|
"build has no owner property for Gitea.")
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
sha = unicode2NativeString(sha)
|
||||||
|
state = unicode2NativeString(state)
|
||||||
|
target_url = unicode2NativeString(build['url'])
|
||||||
|
context = unicode2NativeString(context)
|
||||||
|
description = unicode2NativeString(description)
|
||||||
|
res = yield self.createStatus(
|
||||||
|
project_owner=repository_owner,
|
||||||
|
repo_name=repository_name,
|
||||||
|
sha=sha,
|
||||||
|
state=state,
|
||||||
|
target_url=target_url,
|
||||||
|
context=context,
|
||||||
|
description=description
|
||||||
|
)
|
||||||
|
if res.code not in (200, 201, 204):
|
||||||
|
message = yield res.json()
|
||||||
|
message = message.get('message', 'unspecified error')
|
||||||
|
log.msg(
|
||||||
|
'Could not send status "{state}" for '
|
||||||
|
'{repo} at {sha}: {message}'.format(
|
||||||
|
state=state,
|
||||||
|
repo=sourcestamp['repository'], sha=sha,
|
||||||
|
message=message))
|
||||||
|
elif self.verbose:
|
||||||
|
log.msg(
|
||||||
|
'Status "{state}" sent for '
|
||||||
|
'{repo} at {sha}.'.format(
|
||||||
|
state=state,
|
||||||
|
repo=sourcestamp['repository'], 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
|
||||||
|
))
|
162
buildbot_gitea/test/test_reporter.py
Normal file
162
buildbot_gitea/test/test_reporter.py
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
# Based on TestGitLabStatusPush from buildbot
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
from mock import Mock
|
||||||
|
|
||||||
|
from twisted.internet import defer
|
||||||
|
from twisted.trial import unittest
|
||||||
|
|
||||||
|
from buildbot import config
|
||||||
|
from buildbot.process.properties import Interpolate
|
||||||
|
from buildbot.process.results import FAILURE
|
||||||
|
from buildbot.process.results import SUCCESS
|
||||||
|
from buildbot_gitea.reporter import GiteaStatusPush
|
||||||
|
from buildbot.test.fake import fakemaster
|
||||||
|
from buildbot.test.fake import httpclientservice as fakehttpclientservice
|
||||||
|
from buildbot.test.util import logging
|
||||||
|
from buildbot.test.util.reporter import ReporterTestMixin
|
||||||
|
|
||||||
|
|
||||||
|
class TestGiteaStatusPush(
|
||||||
|
unittest.TestCase,
|
||||||
|
ReporterTestMixin,
|
||||||
|
logging.LoggingMixin):
|
||||||
|
# repository must be in the form http://gitea/<owner>/<project>
|
||||||
|
TEST_REPO = u'http://gitea/buildbot/buildbot'
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def setUp(self):
|
||||||
|
# ignore config error if txrequests is not installed
|
||||||
|
self.patch(config, '_errors', Mock())
|
||||||
|
self.master = fakemaster.make_master(testcase=self,
|
||||||
|
wantData=True, wantDb=True, wantMq=True)
|
||||||
|
|
||||||
|
yield self.master.startService()
|
||||||
|
self._http = yield fakehttpclientservice.HTTPClientService.getFakeService(
|
||||||
|
self.master, self,
|
||||||
|
"http://gitea", headers={'AuthorizationHeaderToken': 'token XXYYZZ'},
|
||||||
|
debug=None, verify=None)
|
||||||
|
self.sp = sp = GiteaStatusPush("http://gitea/", Interpolate('XXYYZZ'))
|
||||||
|
sp.sessionFactory = Mock(return_value=Mock())
|
||||||
|
|
||||||
|
yield sp.setServiceParent(self.master)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
return self.master.stopService()
|
||||||
|
|
||||||
|
def setupProps(self):
|
||||||
|
self.TEST_PROPS['owner'] = "buildbot"
|
||||||
|
self.TEST_PROPS['repository_name'] = "buildbot"
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def setupBuildResults(self, buildResults):
|
||||||
|
self.insertTestData([buildResults], buildResults)
|
||||||
|
build = yield self.master.data.get(("builds", 20))
|
||||||
|
defer.returnValue(build)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def test_basic(self):
|
||||||
|
self.setupProps()
|
||||||
|
build = yield self.setupBuildResults(SUCCESS)
|
||||||
|
# we make sure proper calls to txrequests have been made
|
||||||
|
self._http.expect(
|
||||||
|
'post',
|
||||||
|
'/api/v1/repos/buildbot/buildbot/statuses/d34db33fd43db33f',
|
||||||
|
json={'state': 'pending',
|
||||||
|
'target_url': 'http://localhost:8080/#builders/79/builds/0',
|
||||||
|
'description': 'Build started.', 'name': 'buildbot/Builder0'})
|
||||||
|
self._http.expect(
|
||||||
|
'post',
|
||||||
|
'/api/v1/repos/buildbot/buildbot/statuses/d34db33fd43db33f',
|
||||||
|
json={'state': 'success',
|
||||||
|
'target_url': 'http://localhost:8080/#builders/79/builds/0',
|
||||||
|
'description': 'Build done.', 'name': 'buildbot/Builder0'})
|
||||||
|
self._http.expect(
|
||||||
|
'post',
|
||||||
|
'/api/v1/repos/buildbot/buildbot/statuses/d34db33fd43db33f',
|
||||||
|
json={'state': 'failure',
|
||||||
|
'target_url': 'http://localhost:8080/#builders/79/builds/0',
|
||||||
|
'description': 'Build done.', 'name': 'buildbot/Builder0'})
|
||||||
|
|
||||||
|
build['complete'] = False
|
||||||
|
self.sp.buildStarted(("build", 20, "started"), build)
|
||||||
|
build['complete'] = True
|
||||||
|
self.sp.buildFinished(("build", 20, "finished"), build)
|
||||||
|
build['results'] = FAILURE
|
||||||
|
self.sp.buildFinished(("build", 20, "finished"), build)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def test_sshurl(self):
|
||||||
|
self.setupProps()
|
||||||
|
self.TEST_REPO = u'git@gitea:buildbot/buildbot.git'
|
||||||
|
build = yield self.setupBuildResults(SUCCESS)
|
||||||
|
# we make sure proper calls to txrequests have been made
|
||||||
|
self._http.expect(
|
||||||
|
'post',
|
||||||
|
'/api/v1/repos/buildbot/buildbot/statuses/d34db33fd43db33f',
|
||||||
|
json={'state': 'pending',
|
||||||
|
'target_url': 'http://localhost:8080/#builders/79/builds/0',
|
||||||
|
'description': 'Build started.', 'name': 'buildbot/Builder0'})
|
||||||
|
build['complete'] = False
|
||||||
|
self.sp.buildStarted(("build", 20, "started"), build)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def test_noowner(self):
|
||||||
|
self.setUpLogging()
|
||||||
|
self.setupProps()
|
||||||
|
del self.TEST_PROPS["owner"]
|
||||||
|
self.TEST_REPO = u''
|
||||||
|
build = yield self.setupBuildResults(SUCCESS)
|
||||||
|
build['complete'] = False
|
||||||
|
self.sp.buildStarted(("build", 20, "started"), build)
|
||||||
|
# implicit check that no http request is done
|
||||||
|
self.assertLogged("Could not send status, "
|
||||||
|
"build has no owner property for Gitea.")
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def test_noreponame(self):
|
||||||
|
self.setUpLogging()
|
||||||
|
self.setupProps()
|
||||||
|
del self.TEST_PROPS["repository_name"]
|
||||||
|
self.TEST_REPO = u''
|
||||||
|
build = yield self.setupBuildResults(SUCCESS)
|
||||||
|
build['complete'] = False
|
||||||
|
self.sp.buildStarted(("build", 20, "started"), build)
|
||||||
|
# implicit check that no http request is done
|
||||||
|
self.assertLogged("Could not send status, "
|
||||||
|
"build has no repository_name property for Gitea.")
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def test_senderror(self):
|
||||||
|
self.setupProps()
|
||||||
|
self.setUpLogging()
|
||||||
|
build = yield self.setupBuildResults(SUCCESS)
|
||||||
|
# we make sure proper calls to txrequests have been made
|
||||||
|
self._http.expect(
|
||||||
|
'post',
|
||||||
|
'/api/v1/repos/buildbot/buildbot/statuses/d34db33fd43db33f',
|
||||||
|
json={'state': 'pending',
|
||||||
|
'target_url': 'http://localhost:8080/#builders/79/builds/0',
|
||||||
|
'description': 'Build started.', 'name': 'buildbot/Builder0'},
|
||||||
|
content_json={'message': 'sha1 not found for branch master'},
|
||||||
|
code=404)
|
||||||
|
build['complete'] = False
|
||||||
|
self.sp.buildStarted(("build", 20, "started"), build)
|
||||||
|
self.assertLogged(
|
||||||
|
"Could not send status \"pending\" for "
|
||||||
|
"http://gitea/buildbot/buildbot at d34db33fd43db33f:"
|
||||||
|
" sha1 not found for branch master")
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def test_badchange(self):
|
||||||
|
self.setupProps()
|
||||||
|
self.setUpLogging()
|
||||||
|
build = yield self.setupBuildResults(SUCCESS)
|
||||||
|
# we make sure proper calls to txrequests have been made
|
||||||
|
build['complete'] = False
|
||||||
|
self.sp.buildStarted(("build", 20, "started"), build)
|
||||||
|
self.assertLogged("Failed to send status \"pending\" for"
|
||||||
|
" http://gitea/buildbot/buildbot at d34db33fd43db33f")
|
||||||
|
self.flushLoggedErrors(AssertionError)
|
|
@ -43,6 +43,8 @@ class GiteaHandler(BaseHookHandler):
|
||||||
'category': event_type,
|
'category': event_type,
|
||||||
'properties': {
|
'properties': {
|
||||||
'event': event_type,
|
'event': event_type,
|
||||||
|
'repository_name': repository['name'],
|
||||||
|
'owner': repository["owner"]["username"]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if codebase is not None:
|
if codebase is not None:
|
||||||
|
@ -97,6 +99,8 @@ class GiteaHandler(BaseHookHandler):
|
||||||
'head_git_ssh_url': head['repo']['ssh_url'],
|
'head_git_ssh_url': head['repo']['ssh_url'],
|
||||||
'pr_id': pull_request['id'],
|
'pr_id': pull_request['id'],
|
||||||
'pr_number': pull_request['number'],
|
'pr_number': pull_request['number'],
|
||||||
|
'repository_name': repository['name'],
|
||||||
|
'owner': repository["owner"]["username"],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if codebase is not None:
|
if codebase is not None:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user