Initial transformation into transifex
This commit is contained in:
parent
1d10fc0e11
commit
5885c8cbbe
|
@ -1,4 +1,4 @@
|
||||||
# Buildbot Gitea Plugin
|
# Buildbot Transifex Plugin
|
||||||
|
|
||||||
|
|
||||||
[![PyPI version](https://badge.fury.io/py/buildbot-gitea.svg)](https://badge.fury.io/py/buildbot-gitea)
|
[![PyPI version](https://badge.fury.io/py/buildbot-gitea.svg)](https://badge.fury.io/py/buildbot-gitea)
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
from buildbot.www.oauth2 import OAuth2Auth
|
|
||||||
from urllib.parse import urljoin
|
|
||||||
|
|
||||||
|
|
||||||
class GiteaAuth(OAuth2Auth):
|
|
||||||
name = 'Gitea'
|
|
||||||
faIcon = 'mug-tea'
|
|
||||||
|
|
||||||
AUTH_URL = 'login/oauth/authorize'
|
|
||||||
TOKEN_URL = 'login/oauth/access_token'
|
|
||||||
|
|
||||||
def __init__(self, endpoint, client_id, client_secret, **kwargs):
|
|
||||||
super(GiteaAuth, self).__init__(client_id, client_secret, **kwargs)
|
|
||||||
self.resourceEndpoint = endpoint
|
|
||||||
self.authUri = urljoin(endpoint, self.AUTH_URL)
|
|
||||||
self.tokenUri = urljoin(endpoint, self.TOKEN_URL)
|
|
||||||
|
|
||||||
def getUserInfoFromOAuthClient(self, c):
|
|
||||||
return self.get(c, '/api/v1/user')
|
|
|
@ -1,229 +0,0 @@
|
||||||
# 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.warnings import warn_deprecated
|
|
||||||
from buildbot.reporters.generators.build import BuildStartEndStatusGenerator
|
|
||||||
from buildbot.reporters.message import MessageFormatterRenderable
|
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
|
|
||||||
class GiteaStatusPush(http.ReporterBase):
|
|
||||||
name = "GiteaStatusPush"
|
|
||||||
ssh_url_match = re.compile(r"(ssh://)?[\w+\-\_]+@[\w\.\-\_]+:?(\d*/)?(?P<owner>[\w_\-\.]+)/(?P<repo_name>[\w_\-\.]+?)(\.git)?$")
|
|
||||||
|
|
||||||
def checkConfig(self, baseURL, token,
|
|
||||||
context=None, context_pr=None, verbose=False,
|
|
||||||
debug=None, verify=None,
|
|
||||||
generators=None,
|
|
||||||
warningAsSuccess=False, **kwargs):
|
|
||||||
|
|
||||||
if generators is None:
|
|
||||||
generators = self._create_default_generators()
|
|
||||||
|
|
||||||
super().checkConfig(generators=generators, **kwargs)
|
|
||||||
httpclientservice.HTTPClientService.checkAvailable(
|
|
||||||
self.__class__.__name__)
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def reconfigService(self, baseURL, token,
|
|
||||||
context=None, context_pr=None, verbose=False,
|
|
||||||
debug=None, verify=None,
|
|
||||||
generators=None,
|
|
||||||
warningAsSuccess=False, **kwargs):
|
|
||||||
|
|
||||||
token = yield self.renderSecrets(token)
|
|
||||||
self.debug = debug
|
|
||||||
self.verify = verify
|
|
||||||
self.verbose = verbose
|
|
||||||
if generators is None:
|
|
||||||
generators = self._create_default_generators()
|
|
||||||
|
|
||||||
yield super().reconfigService(generators=generators, **kwargs)
|
|
||||||
|
|
||||||
self.context = context or Interpolate('buildbot/%(prop:buildername)s')
|
|
||||||
self.context_pr = context_pr or \
|
|
||||||
Interpolate('buildbot/pull_request/%(prop:buildername)s')
|
|
||||||
if baseURL.endswith('/'):
|
|
||||||
baseURL = baseURL[:-1]
|
|
||||||
self.baseURL = baseURL
|
|
||||||
self._http = yield httpclientservice.HTTPClientService.getService(
|
|
||||||
self.master, baseURL,
|
|
||||||
headers={'Authorization': 'token {}'.format(token)},
|
|
||||||
debug=self.debug, verify=self.verify)
|
|
||||||
self.verbose = verbose
|
|
||||||
self.project_ids = {}
|
|
||||||
self.warningAsSuccess = warningAsSuccess
|
|
||||||
|
|
||||||
def _create_default_generators(self):
|
|
||||||
start_formatter = MessageFormatterRenderable('Build started.')
|
|
||||||
end_formatter = MessageFormatterRenderable('Build done.')
|
|
||||||
|
|
||||||
return [
|
|
||||||
BuildStartEndStatusGenerator(start_formatter=start_formatter,
|
|
||||||
end_formatter=end_formatter)
|
|
||||||
]
|
|
||||||
|
|
||||||
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['context'] = 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):
|
|
||||||
# the only case when this function is called is when the user derives this class, overrides
|
|
||||||
# send() and calls super().send(build) from there.
|
|
||||||
yield self._send_impl(build)
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def sendMessage(self, reports):
|
|
||||||
build = reports[0]['builds'][0]
|
|
||||||
if self.send.__func__ is not GiteaStatusPush.send:
|
|
||||||
warn_deprecated('2.9.0', 'send() in reporters has been deprecated. Use sendMessage()')
|
|
||||||
yield self.send(build)
|
|
||||||
else:
|
|
||||||
yield self._send_impl(reports)
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def _send_impl(self, reports):
|
|
||||||
report = reports[0]
|
|
||||||
build = report['builds'][0]
|
|
||||||
props = Properties.fromDict(build['properties'])
|
|
||||||
props.master = self.master
|
|
||||||
|
|
||||||
description = report.get('body', None)
|
|
||||||
|
|
||||||
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')
|
|
||||||
else:
|
|
||||||
state = 'pending'
|
|
||||||
|
|
||||||
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']
|
|
||||||
repository_owner = None
|
|
||||||
if sha is None:
|
|
||||||
# No special revision for this, so ignore it
|
|
||||||
continue
|
|
||||||
# If this is a pull request, send the status to the head repository
|
|
||||||
if 'pr_id' in props:
|
|
||||||
repository_name = props['head_reponame']
|
|
||||||
repository_owner = props['head_owner']
|
|
||||||
sha = props['head_sha']
|
|
||||||
elif 'repository_name' in props:
|
|
||||||
repository_name = props['repository_name']
|
|
||||||
else:
|
|
||||||
match = re.match(self.ssh_url_match, sourcestamp['repository'])
|
|
||||||
if match is not None:
|
|
||||||
repository_name = match.group("repo_name")
|
|
||||||
else:
|
|
||||||
log.msg(
|
|
||||||
"Could not send status, "
|
|
||||||
"build has no repository_name property for Gitea.")
|
|
||||||
continue
|
|
||||||
if repository_owner is None:
|
|
||||||
if 'owner' in props:
|
|
||||||
repository_owner = props['owner']
|
|
||||||
else:
|
|
||||||
match = re.match(self.ssh_url_match, sourcestamp['repository'])
|
|
||||||
if match is not None:
|
|
||||||
repository_owner = match.group("owner")
|
|
||||||
else:
|
|
||||||
log.msg(
|
|
||||||
"Could not send status, "
|
|
||||||
"build has no owner property for Gitea.")
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
target_url = build['url']
|
|
||||||
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}: {code} : {message}'.format(
|
|
||||||
state=state,
|
|
||||||
repo=sourcestamp['repository'], sha=sha,
|
|
||||||
code=res.code,
|
|
||||||
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
|
|
||||||
))
|
|
|
@ -1,33 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
from twisted.internet import defer
|
|
||||||
from twisted.python import log
|
|
||||||
|
|
||||||
from buildbot.steps.source.git import Git
|
|
||||||
|
|
||||||
|
|
||||||
class Gitea(Git):
|
|
||||||
"""
|
|
||||||
Source step that knows how to handle merge requests from
|
|
||||||
the Gitea webhook
|
|
||||||
"""
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def _fetch(self, *args, **kwargs):
|
|
||||||
res = yield super(Gitea, self)._fetch(*args, **kwargs)
|
|
||||||
if self.build.hasProperty("pr_id"):
|
|
||||||
remote = yield self._dovccmd(
|
|
||||||
['config', 'remote.pr_source.url'], collectStdout=True, abandonOnFailure=False)
|
|
||||||
if remote is None or remote.strip() is '':
|
|
||||||
yield self._dovccmd(
|
|
||||||
['remote', 'add', 'pr_source',
|
|
||||||
self.build.getProperty("head_git_ssh_url", None)])
|
|
||||||
else:
|
|
||||||
yield self._dovccmd(
|
|
||||||
['remote', 'set-url', 'pr_source',
|
|
||||||
self.build.getProperty("head_git_ssh_url", None)])
|
|
||||||
yield self._dovccmd(['fetch', 'pr_source'])
|
|
||||||
res = yield self._dovccmd(['merge', self.build.getProperty("head_sha", None)])
|
|
||||||
defer.returnValue(res)
|
|
|
@ -1,88 +0,0 @@
|
||||||
import json
|
|
||||||
import mock
|
|
||||||
from buildbot.process.properties import Secret
|
|
||||||
from buildbot.test.util.config import ConfigErrorsMixin
|
|
||||||
from buildbot.test.util.misc import TestReactorMixin
|
|
||||||
from buildbot.test.util import www
|
|
||||||
from twisted.internet import defer
|
|
||||||
from twisted.trial import unittest
|
|
||||||
from buildbot.secrets.manager import SecretManager
|
|
||||||
from buildbot.test.fake.secrets import FakeSecretStorage
|
|
||||||
|
|
||||||
from buildbot_gitea.auth import GiteaAuth
|
|
||||||
|
|
||||||
try:
|
|
||||||
import requests
|
|
||||||
except ImportError:
|
|
||||||
requests = None
|
|
||||||
|
|
||||||
|
|
||||||
class FakeResponse:
|
|
||||||
|
|
||||||
def __init__(self, _json):
|
|
||||||
self.json = lambda: _json
|
|
||||||
self.content = json.dumps(_json)
|
|
||||||
|
|
||||||
def raise_for_status(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TestGiteaAuth(TestReactorMixin, www.WwwTestMixin, ConfigErrorsMixin,
|
|
||||||
unittest.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.setUpTestReactor()
|
|
||||||
if requests is None:
|
|
||||||
raise unittest.SkipTest("Need to install requests to test oauth2")
|
|
||||||
|
|
||||||
self.patch(requests, 'request', mock.Mock(spec=requests.request))
|
|
||||||
self.patch(requests, 'post', mock.Mock(spec=requests.post))
|
|
||||||
self.patch(requests, 'get', mock.Mock(spec=requests.get))
|
|
||||||
|
|
||||||
self.giteaAuth = GiteaAuth(
|
|
||||||
'https://gitea.test',
|
|
||||||
'client-id',
|
|
||||||
'client-secret')
|
|
||||||
self._master = master = self.make_master(
|
|
||||||
url='h:/a/b/', auth=self.giteaAuth)
|
|
||||||
self.giteaAuth.reconfigAuth(master, master.config)
|
|
||||||
|
|
||||||
self.giteaAuth_secret = GiteaAuth(
|
|
||||||
'https://gitea.test',
|
|
||||||
Secret("client-id"),
|
|
||||||
Secret("client-secret"))
|
|
||||||
self._master = master = self.make_master(
|
|
||||||
url='h:/a/b/', auth=self.giteaAuth_secret)
|
|
||||||
fake_storage_service = FakeSecretStorage()
|
|
||||||
fake_storage_service.reconfigService(
|
|
||||||
secretdict={
|
|
||||||
"client-id": "secretClientId",
|
|
||||||
"client-secret": "secretClientSecret"
|
|
||||||
})
|
|
||||||
secret_service = SecretManager()
|
|
||||||
secret_service.services = [fake_storage_service]
|
|
||||||
secret_service.setServiceParent(self._master)
|
|
||||||
self.giteaAuth_secret.reconfigAuth(master, master.config)
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def test_getGiteaLoginURL(self):
|
|
||||||
res = yield self.giteaAuth.getLoginURL('http://redir')
|
|
||||||
exp = ("https://gitea.test/login/oauth/authorize?client_id=client-id&"
|
|
||||||
"redirect_uri=h%3A%2Fa%2Fb%2Fauth%2Flogin&response_type=code&"
|
|
||||||
"state=redirect%3Dhttp%253A%252F%252Fredir")
|
|
||||||
self.assertEqual(res, exp)
|
|
||||||
res = yield self.giteaAuth.getLoginURL(None)
|
|
||||||
exp = ("https://gitea.test/login/oauth/authorize?client_id=client-id&"
|
|
||||||
"redirect_uri=h%3A%2Fa%2Fb%2Fauth%2Flogin&response_type=code")
|
|
||||||
self.assertEqual(res, exp)
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def test_getGiteaLoginURL_with_secret(self):
|
|
||||||
res = yield self.giteaAuth_secret.getLoginURL('http://redir')
|
|
||||||
exp = ("https://gitea.test/login/oauth/authorize?client_id=secretClientId&"
|
|
||||||
"redirect_uri=h%3A%2Fa%2Fb%2Fauth%2Flogin&response_type=code&"
|
|
||||||
"state=redirect%3Dhttp%253A%252F%252Fredir")
|
|
||||||
self.assertEqual(res, exp)
|
|
||||||
res = yield self.giteaAuth_secret.getLoginURL(None)
|
|
||||||
exp = ("https://gitea.test/login/oauth/authorize?client_id=secretClientId&"
|
|
||||||
"redirect_uri=h%3A%2Fa%2Fb%2Fauth%2Flogin&response_type=code")
|
|
||||||
self.assertEqual(res, exp)
|
|
|
@ -1,217 +0,0 @@
|
||||||
# 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
|
|
||||||
from buildbot.test.util.misc import TestReactorMixin
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TestGiteaStatusPush(
|
|
||||||
unittest.TestCase,
|
|
||||||
ReporterTestMixin,
|
|
||||||
logging.LoggingMixin,
|
|
||||||
TestReactorMixin):
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def setUp(self):
|
|
||||||
self.setUpTestReactor()
|
|
||||||
|
|
||||||
self.setup_reporter_test()
|
|
||||||
|
|
||||||
# repository must be in the form http://gitea/<owner>/<project>
|
|
||||||
self.reporter_test_repo = u'http://gitea/buildbot/buildbot'
|
|
||||||
|
|
||||||
# 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.getService(
|
|
||||||
self.master, self,
|
|
||||||
"http://gitea", headers={'Authorization': 'token XXYYZZ'},
|
|
||||||
debug=None, verify=None)
|
|
||||||
self.sp = GiteaStatusPush("http://gitea/", Interpolate('XXYYZZ'))
|
|
||||||
|
|
||||||
yield self.sp.setServiceParent(self.master)
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
return self.master.stopService()
|
|
||||||
|
|
||||||
def setupProps(self):
|
|
||||||
self.reporter_test_props['owner'] = "buildbot"
|
|
||||||
self.reporter_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.', 'context': '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.', 'context': '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.', 'context': 'buildbot/Builder0'})
|
|
||||||
|
|
||||||
build['complete'] = False
|
|
||||||
self.sp._got_event(('builds', 20, 'new'), build)
|
|
||||||
build['complete'] = True
|
|
||||||
self.sp._got_event(('builds', 20, 'finished'), build)
|
|
||||||
build['results'] = FAILURE
|
|
||||||
self.sp._got_event(('builds', 20, 'finished'), build)
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def test_pullrequest(self):
|
|
||||||
self.setupProps()
|
|
||||||
self.reporter_test_props["pr_id"] = 42
|
|
||||||
self.reporter_test_props["head_owner"] = 'foo'
|
|
||||||
self.reporter_test_props["head_reponame"] = 'bar'
|
|
||||||
self.reporter_test_props["head_sha"] = '52c7864e56d1425f4c0a76c1e692942047bdd849'
|
|
||||||
build = yield self.setupBuildResults(SUCCESS)
|
|
||||||
# we make sure proper calls to txrequests have been made
|
|
||||||
self._http.expect(
|
|
||||||
'post',
|
|
||||||
'/api/v1/repos/foo/bar/statuses/52c7864e56d1425f4c0a76c1e692942047bdd849',
|
|
||||||
json={'state': 'success',
|
|
||||||
'target_url': 'http://localhost:8080/#builders/79/builds/0',
|
|
||||||
'description': 'Build done.', 'context': 'buildbot/pull_request/Builder0'})
|
|
||||||
|
|
||||||
build['complete'] = True
|
|
||||||
self.sp._got_event(('builds', 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.', 'context': 'buildbot/Builder0'})
|
|
||||||
build['complete'] = False
|
|
||||||
self.sp._got_event(('builds', 20, 'new'), build)
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def test_sshurl_noprops(self):
|
|
||||||
self.reporter_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.', 'context': 'buildbot/Builder0'})
|
|
||||||
build['complete'] = False
|
|
||||||
self.sp._got_event(('builds', 20, 'new'), build)
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def test_noowner(self):
|
|
||||||
self.setUpLogging()
|
|
||||||
self.setupProps()
|
|
||||||
del self.reporter_test_props["owner"]
|
|
||||||
self.TEST_REPO = u''
|
|
||||||
build = yield self.setupBuildResults(SUCCESS)
|
|
||||||
build['complete'] = False
|
|
||||||
self.sp._got_event(('builds', 20, 'new'), 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.reporter_test_props["repository_name"]
|
|
||||||
self.TEST_REPO = u''
|
|
||||||
build = yield self.setupBuildResults(SUCCESS)
|
|
||||||
build['complete'] = False
|
|
||||||
self.sp._got_event(('builds', 20, 'new'), 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.insert_build_new()
|
|
||||||
# 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.', 'context': 'buildbot/Builder0'},
|
|
||||||
content_json={
|
|
||||||
"message": "sha1 not found: d34db33fd43db33f",
|
|
||||||
"url": "https://godoc.org/github.com/go-gitea/go-sdk/gitea"
|
|
||||||
},
|
|
||||||
code=500)
|
|
||||||
build['complete'] = False
|
|
||||||
self.sp._got_event(("builds", 20, "new"), build)
|
|
||||||
self.assertLogged(
|
|
||||||
"Could not send status \"pending\" for "
|
|
||||||
"http://gitea/buildbot/buildbot at d34db33fd43db33f:"
|
|
||||||
" 500 : sha1 not found: d34db33fd43db33f")
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def test_badchange(self):
|
|
||||||
self.setupProps()
|
|
||||||
self.setUpLogging()
|
|
||||||
build = yield self.insert_build_new()
|
|
||||||
# we make sure proper calls to txrequests have been made
|
|
||||||
self._http.expect(
|
|
||||||
'post',
|
|
||||||
'/api/v1/repos/buildbot/buildbot/statuses/d34db33fd43db33f',
|
|
||||||
json={
|
|
||||||
'state': 'pending',
|
|
||||||
'description': 'Build started.',
|
|
||||||
'target_url': 'http://localhost:8080/#builders/79/builds/0',
|
|
||||||
'context': 'buildbot/Builder0'
|
|
||||||
},
|
|
||||||
content_json={"message": "Not found"},
|
|
||||||
code=404,
|
|
||||||
)
|
|
||||||
build['complete'] = False
|
|
||||||
yield self.sp._got_event(("builds", 20, "new"), build)
|
|
||||||
self.assertLogged("Could not send status \"pending\" for"
|
|
||||||
" http://gitea/buildbot/buildbot at d34db33fd43db33f")
|
|
||||||
self.flushLoggedErrors(AssertionError)
|
|
|
@ -1,107 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
from twisted.trial import unittest
|
|
||||||
|
|
||||||
from buildbot.process.results import SUCCESS
|
|
||||||
from buildbot_gitea.step_source import Gitea
|
|
||||||
from buildbot.test.fake.remotecommand import Expect
|
|
||||||
from buildbot.test.fake.remotecommand import ExpectShell
|
|
||||||
from buildbot.test.util import config
|
|
||||||
from buildbot.test.util import sourcesteps
|
|
||||||
from buildbot.test.util.misc import TestReactorMixin
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TestGitea(sourcesteps.SourceStepMixin, config.ConfigErrorsMixin, unittest.TestCase, TestReactorMixin):
|
|
||||||
stepClass = Gitea
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.setUpTestReactor()
|
|
||||||
self.sourceName = self.stepClass.__name__
|
|
||||||
return self.setUpSourceStep()
|
|
||||||
|
|
||||||
def setupStep(self, step, **kwargs):
|
|
||||||
step = sourcesteps.SourceStepMixin.setupStep(self, step, **kwargs)
|
|
||||||
step.build.properties.setProperty("pr_id", "1", "gitea pr id")
|
|
||||||
step.build.properties.setProperty("base_sha", "f6ad368298bd941e934a41f3babc827b2aa95a1d", "gitea source branch")
|
|
||||||
step.build.properties.setProperty("base_branch", "master", "gitea source branch")
|
|
||||||
step.build.properties.setProperty("base_git_ssh_url",
|
|
||||||
"git@gitea.example.com:base/awesome_project.git",
|
|
||||||
"gitea source git ssh url")
|
|
||||||
step.build.properties.setProperty("head_sha", "e4cd1224c622d46a8199c85c858485723115d2c8", "gitea target sha")
|
|
||||||
step.build.properties.setProperty("head_branch", "feature-branch", "gitea target branch")
|
|
||||||
step.build.properties.setProperty("head_git_ssh_url",
|
|
||||||
"git@gitea.example.com:target/awesome_project.git",
|
|
||||||
"gitea target git ssh url")
|
|
||||||
return step
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
return self.tearDownSourceStep()
|
|
||||||
|
|
||||||
def test_with_merge_branch(self):
|
|
||||||
self.setupStep(
|
|
||||||
Gitea(repourl='git@gitea.example.com:base/awesome_project.git',
|
|
||||||
mode='full', method='clean'))
|
|
||||||
|
|
||||||
self.expectCommands(
|
|
||||||
ExpectShell(workdir='wkdir',
|
|
||||||
command=['git', '--version'])
|
|
||||||
+ ExpectShell.log('stdio',
|
|
||||||
stdout='git version 1.7.5')
|
|
||||||
+ 0,
|
|
||||||
Expect('stat', dict(file='wkdir/.buildbot-patched',
|
|
||||||
logEnviron=True))
|
|
||||||
+ 1,
|
|
||||||
Expect('listdir', {'dir': 'wkdir', 'logEnviron': True,
|
|
||||||
'timeout': 1200})
|
|
||||||
+ Expect.update('files', ['.git'])
|
|
||||||
+ 0,
|
|
||||||
ExpectShell(workdir='wkdir',
|
|
||||||
command=['git', 'clean', '-f', '-f', '-d'])
|
|
||||||
+ 0,
|
|
||||||
# here we always ignore revision, and fetch the merge branch
|
|
||||||
ExpectShell(workdir='wkdir',
|
|
||||||
command=['git', 'fetch', '-f', '-t',
|
|
||||||
'git@gitea.example.com:base/awesome_project.git', 'HEAD', '--progress'])
|
|
||||||
+ 0,
|
|
||||||
ExpectShell(workdir='wkdir',
|
|
||||||
command=['git', 'reset', '--hard', 'FETCH_HEAD', '--'])
|
|
||||||
+ 0,
|
|
||||||
ExpectShell(workdir='wkdir',
|
|
||||||
command=['git', 'config', 'remote.pr_source.url'])
|
|
||||||
+ 0,
|
|
||||||
ExpectShell(workdir='wkdir',
|
|
||||||
command=['git', 'remote', 'add', 'pr_source', 'git@gitea.example.com:target/awesome_project.git'])
|
|
||||||
+ 0,
|
|
||||||
ExpectShell(workdir='wkdir',
|
|
||||||
command=['git', 'fetch', 'pr_source'])
|
|
||||||
+ 0,
|
|
||||||
ExpectShell(workdir='wkdir',
|
|
||||||
command=['git', 'merge', 'e4cd1224c622d46a8199c85c858485723115d2c8'])
|
|
||||||
+ 0,
|
|
||||||
ExpectShell(workdir='wkdir',
|
|
||||||
command=['git', 'rev-parse', 'HEAD'])
|
|
||||||
+ ExpectShell.log('stdio',
|
|
||||||
stdout='e4cd1224c622d46a8199c85c858485723115d2c8')
|
|
||||||
+ 0,
|
|
||||||
)
|
|
||||||
self.expectOutcome(result=SUCCESS)
|
|
||||||
self.expectProperty(
|
|
||||||
'got_revision', 'e4cd1224c622d46a8199c85c858485723115d2c8', 'Gitea')
|
|
||||||
return self.runStep()
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import base64
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import hmac
|
import hmac
|
||||||
|
@ -11,13 +12,14 @@ from twisted.python import log
|
||||||
|
|
||||||
from dateutil.parser import parse as dateparse
|
from dateutil.parser import parse as dateparse
|
||||||
|
|
||||||
_HEADER_EVENT_TYPE = 'X-Gitea-Event'
|
_HEADER_USER_AGENT = 'User-Agent'
|
||||||
_HEADER_SIGNATURE = 'X-Gitea-Signature'
|
_HEADER_SIGNATURE = 'X-TX-Signature'
|
||||||
|
_EVENT_KEY = 'event'
|
||||||
|
|
||||||
|
|
||||||
class GiteaHandler(BaseHookHandler):
|
class TransifexHandler(BaseHookHandler):
|
||||||
|
|
||||||
def process_push(self, payload, event_type, codebase):
|
def process_translation_completed(self, payload, event_type, codebase):
|
||||||
refname = payload["ref"]
|
refname = payload["ref"]
|
||||||
|
|
||||||
changes = []
|
changes = []
|
||||||
|
@ -66,7 +68,7 @@ class GiteaHandler(BaseHookHandler):
|
||||||
changes.insert(0, change)
|
changes.insert(0, change)
|
||||||
return changes
|
return changes
|
||||||
|
|
||||||
def process_pull_request(self, payload, event_type, codebase):
|
def process_review_compoleted(self, payload, event_type, codebase):
|
||||||
action = payload['action']
|
action = payload['action']
|
||||||
|
|
||||||
# Only handle potential new stuff, ignore close/.
|
# Only handle potential new stuff, ignore close/.
|
||||||
|
@ -123,6 +125,14 @@ class GiteaHandler(BaseHookHandler):
|
||||||
change['codebase'] = codebase
|
change['codebase'] = codebase
|
||||||
return [change]
|
return [change]
|
||||||
|
|
||||||
|
def _transform_variables(payload):
|
||||||
|
retval = {
|
||||||
|
project: payload.get('project'),
|
||||||
|
repository = [payload.get('resource')],
|
||||||
|
branch = payload.get('language')
|
||||||
|
}
|
||||||
|
return retval
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def getChanges(self, request):
|
def getChanges(self, request):
|
||||||
secret = None
|
secret = None
|
||||||
|
@ -146,39 +156,38 @@ class GiteaHandler(BaseHookHandler):
|
||||||
digestmod=hashlib.sha256)
|
digestmod=hashlib.sha256)
|
||||||
header_signature = bytes2unicode(
|
header_signature = bytes2unicode(
|
||||||
request.getHeader(_HEADER_SIGNATURE))
|
request.getHeader(_HEADER_SIGNATURE))
|
||||||
if signature.hexdigest() != header_signature:
|
|
||||||
|
http_verb = 'POST'
|
||||||
|
http_url_path = request.headers('X-TX-Url')
|
||||||
|
http_gmt_date = request.headers('Date')
|
||||||
|
content_md5 = hashlib.md5(content).hexdigest()
|
||||||
|
msg = b'\n'.join([
|
||||||
|
http_verb, http_url_path, http_gmt_date, content_md5
|
||||||
|
])
|
||||||
|
tx_signature = base64.b64encode(
|
||||||
|
hmac.new(
|
||||||
|
key=rendered_secret,
|
||||||
|
msg=msg,
|
||||||
|
digestmod=hashlib.sha256
|
||||||
|
).digest()
|
||||||
|
)
|
||||||
|
if tx_signature() != header_signature:
|
||||||
raise ValueError('Invalid secret')
|
raise ValueError('Invalid secret')
|
||||||
|
|
||||||
event_type = bytes2unicode(request.getHeader(_HEADER_EVENT_TYPE))
|
event_type = bytes2unicode(payload.get(_EVENT_KEY), "None")
|
||||||
log.msg("Received event '{}' from gitea".format(event_type))
|
log.msg("Received event '{}' from transifex".format(event_type))
|
||||||
|
|
||||||
codebases = request.args.get('codebase', [None])
|
codebase = ""
|
||||||
codebase = bytes2unicode(codebases[0])
|
|
||||||
changes = []
|
changes = []
|
||||||
|
|
||||||
handler_function = getattr(self, 'process_{}'.format(event_type), None)
|
handler_function = getattr(self, 'process_{}'.format(event_type), None)
|
||||||
if not handler_function:
|
if not handler_function:
|
||||||
log.msg("Ignoring gitea event '{}'".format(event_type))
|
log.msg("Ignoring transifex event '{}'".format(event_type))
|
||||||
else:
|
else:
|
||||||
changes = handler_function(payload, event_type, codebase)
|
changes = handler_function(payload, event_type, codebase)
|
||||||
|
|
||||||
return (changes, 'git')
|
return (changes, 'transifex')
|
||||||
|
|
||||||
|
|
||||||
class GiteaHandlerPlugin(BaseHookHandler):
|
|
||||||
def __init__(self, master, options):
|
|
||||||
if not options:
|
|
||||||
options = {}
|
|
||||||
super().__init__(master, options)
|
|
||||||
|
|
||||||
handler_class = options.get('class', GiteaHandler)
|
|
||||||
if 'class' in options:
|
|
||||||
del options['class']
|
|
||||||
|
|
||||||
self.handler = handler_class(master, options)
|
|
||||||
|
|
||||||
def getChanges(self, request):
|
|
||||||
return self.handler.getChanges(request)
|
|
||||||
|
|
||||||
# Plugin name
|
# Plugin name
|
||||||
gitea = GiteaHandlerPlugin
|
transifex = TransifexHandler
|
Loading…
Reference in New Issue
Block a user