From 5885c8cbbed9d353f00639e02c4b6acc91f12f30 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 28 Dec 2022 08:04:44 +0000 Subject: [PATCH] Initial transformation into transifex --- README.md | 2 +- buildbot_gitea/auth.py | 19 -- buildbot_gitea/reporter.py | 229 ------------------ buildbot_gitea/step_source.py | 33 --- buildbot_gitea/test/test_auth.py | 88 ------- buildbot_gitea/test/test_reporter.py | 217 ----------------- buildbot_gitea/test/test_step_source.py | 107 -------- .../__init__.py | 0 .../test/__init__.py | 0 .../test/test_webhook.py | 0 .../webhook.py | 65 ++--- 11 files changed, 38 insertions(+), 722 deletions(-) delete mode 100644 buildbot_gitea/auth.py delete mode 100644 buildbot_gitea/reporter.py delete mode 100644 buildbot_gitea/step_source.py delete mode 100644 buildbot_gitea/test/test_auth.py delete mode 100644 buildbot_gitea/test/test_reporter.py delete mode 100644 buildbot_gitea/test/test_step_source.py rename {buildbot_gitea => buildbot_transifex}/__init__.py (100%) rename {buildbot_gitea => buildbot_transifex}/test/__init__.py (100%) rename {buildbot_gitea => buildbot_transifex}/test/test_webhook.py (100%) rename {buildbot_gitea => buildbot_transifex}/webhook.py (77%) diff --git a/README.md b/README.md index 162e0df..490318f 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/buildbot_gitea/auth.py b/buildbot_gitea/auth.py deleted file mode 100644 index 674001a..0000000 --- a/buildbot_gitea/auth.py +++ /dev/null @@ -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') diff --git a/buildbot_gitea/reporter.py b/buildbot_gitea/reporter.py deleted file mode 100644 index ccb5b3d..0000000 --- a/buildbot_gitea/reporter.py +++ /dev/null @@ -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[\w_\-\.]+)/(?P[\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 - )) diff --git a/buildbot_gitea/step_source.py b/buildbot_gitea/step_source.py deleted file mode 100644 index 0ead578..0000000 --- a/buildbot_gitea/step_source.py +++ /dev/null @@ -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) diff --git a/buildbot_gitea/test/test_auth.py b/buildbot_gitea/test/test_auth.py deleted file mode 100644 index d285895..0000000 --- a/buildbot_gitea/test/test_auth.py +++ /dev/null @@ -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) diff --git a/buildbot_gitea/test/test_reporter.py b/buildbot_gitea/test/test_reporter.py deleted file mode 100644 index 3c0bf97..0000000 --- a/buildbot_gitea/test/test_reporter.py +++ /dev/null @@ -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// - 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) diff --git a/buildbot_gitea/test/test_step_source.py b/buildbot_gitea/test/test_step_source.py deleted file mode 100644 index b2db796..0000000 --- a/buildbot_gitea/test/test_step_source.py +++ /dev/null @@ -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() diff --git a/buildbot_gitea/__init__.py b/buildbot_transifex/__init__.py similarity index 100% rename from buildbot_gitea/__init__.py rename to buildbot_transifex/__init__.py diff --git a/buildbot_gitea/test/__init__.py b/buildbot_transifex/test/__init__.py similarity index 100% rename from buildbot_gitea/test/__init__.py rename to buildbot_transifex/test/__init__.py diff --git a/buildbot_gitea/test/test_webhook.py b/buildbot_transifex/test/test_webhook.py similarity index 100% rename from buildbot_gitea/test/test_webhook.py rename to buildbot_transifex/test/test_webhook.py diff --git a/buildbot_gitea/webhook.py b/buildbot_transifex/webhook.py similarity index 77% rename from buildbot_gitea/webhook.py rename to buildbot_transifex/webhook.py index fe6bce2..f2c4864 100644 --- a/buildbot_gitea/webhook.py +++ b/buildbot_transifex/webhook.py @@ -1,3 +1,4 @@ +import base64 import json import re import hmac @@ -11,13 +12,14 @@ from twisted.python import log from dateutil.parser import parse as dateparse -_HEADER_EVENT_TYPE = 'X-Gitea-Event' -_HEADER_SIGNATURE = 'X-Gitea-Signature' +_HEADER_USER_AGENT = 'User-Agent' +_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"] changes = [] @@ -66,7 +68,7 @@ class GiteaHandler(BaseHookHandler): changes.insert(0, change) return changes - def process_pull_request(self, payload, event_type, codebase): + def process_review_compoleted(self, payload, event_type, codebase): action = payload['action'] # Only handle potential new stuff, ignore close/. @@ -123,6 +125,14 @@ class GiteaHandler(BaseHookHandler): change['codebase'] = codebase return [change] + def _transform_variables(payload): + retval = { + project: payload.get('project'), + repository = [payload.get('resource')], + branch = payload.get('language') + } + return retval + @defer.inlineCallbacks def getChanges(self, request): secret = None @@ -146,39 +156,38 @@ class GiteaHandler(BaseHookHandler): digestmod=hashlib.sha256) header_signature = bytes2unicode( 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') - event_type = bytes2unicode(request.getHeader(_HEADER_EVENT_TYPE)) - log.msg("Received event '{}' from gitea".format(event_type)) + event_type = bytes2unicode(payload.get(_EVENT_KEY), "None") + log.msg("Received event '{}' from transifex".format(event_type)) - codebases = request.args.get('codebase', [None]) - codebase = bytes2unicode(codebases[0]) + codebase = "" changes = [] handler_function = getattr(self, 'process_{}'.format(event_type), None) if not handler_function: - log.msg("Ignoring gitea event '{}'".format(event_type)) + log.msg("Ignoring transifex event '{}'".format(event_type)) else: 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 -gitea = GiteaHandlerPlugin +transifex = TransifexHandler