Compare commits

..

54 Commits

Author SHA1 Message Date
5885c8cbbe Initial transformation into transifex 2022-12-28 08:04:44 +00:00
Marvin Pohl
1d10fc0e11 Bumped version to 1.7.2 2022-09-05 16:15:16 +02:00
László Károlyi
a6754fadba Handle any extra parameters to _fetch 2022-09-05 14:51:20 +02:00
Anton Kasimov
5524f5f53d Allow passing kwargs to OAuth2Auth 2022-01-23 22:56:39 +01:00
Marvin Pohl
fc4d14ecbe Bumped version to 1.7.1 2022-01-22 03:30:08 +01:00
Marvin Pohl
fe9fef407f Fixed None access in commits with no changed, added or removed files 2022-01-22 03:28:32 +01:00
Marvin Pohl
2338fac3cd Bumped version to 1.7.0 2021-07-05 13:53:42 +02:00
Marvin Pohl
16ea6c344a Changed Unittests for new head_sha usage 2021-07-05 13:53:00 +02:00
Marvin Pohl
52c7864e56 Use the HEAD sha, when reporting a PR issue 2021-07-05 13:50:09 +02:00
Marvin Pohl
d1c24a641c
Removed build status since travis ci is broken 2021-06-22 19:37:33 +02:00
Marvin Pohl
eeaebe4d92 Bumped Version to v1.6.1 2021-06-22 19:35:00 +02:00
Marvin Pohl
d55b1dc9ea Fixed not being able to specify a context for the reporter. 2021-06-22 19:34:30 +02:00
Marvin Pohl
294160ad83 Bumped Version to v1.6.0 2021-05-16 01:37:50 +02:00
Marvin Pohl
b4d11a7058 Status reporter now sends status to head repository if the current build is from a pull request. 2021-05-16 01:37:03 +02:00
Marvin Pohl
b1dc019e60 Added unit tests for Secret Phrase provider in webhook 2021-04-26 10:58:14 +02:00
3e59f2069e
Feat: add support for secret provider for webhook 2021-04-16 03:55:32 +02:00
Marvin Pohl
fe223aa990 Bumped Version to v1.5.1 2021-03-29 00:07:39 +02:00
Marvin Pohl
341f216c2c Set the base repository and branch as the default one for a pull request. 2021-03-29 00:06:25 +02:00
Marvin Pohl
284a58826d Bumped Version to 1.5.0 2021-03-20 12:43:18 +01:00
Marvin Pohl
e9905239dc Added unit test for changed files 2021-03-20 12:35:34 +01:00
Marvin Pohl
e2297f3be7 Merge branch 'add-changed-files' of https://github.com/mrstanwell/buildbot-gitea into mrstanwell-add-changed-files 2021-03-20 12:25:05 +01:00
mrstanwell
f3964970d1 Add list of changed files to "changes". 2021-03-17 18:35:06 -05:00
Marvin Pohl
d67eeedbd2 Bumped version to v1.4.1 2021-03-10 20:20:06 +01:00
Marvin Pohl
0c32c93715 Using correct header identifiert for the Gitea Signature 2021-03-10 20:19:37 +01:00
Marvin Pohl
8e66482bec Bumped version to 1.4.0 2021-03-09 21:54:57 +01:00
Marvin Pohl
7171e4a371 Changed buildbot requirements to >=3.0.0 2021-03-09 21:54:27 +01:00
Marvin Pohl
0fd2394bcd Webhook now verifies the new hmac signature instead of just comparing the secret as plain text. 2021-03-09 21:54:06 +01:00
Marvin Pohl
708fad884e Removed start and endDescription from documentation, since this is now being generated using generators. 2021-03-09 20:51:33 +01:00
Marvin Pohl
8d8626b38c Fixed up implementation for buildbot 3.0.0 2021-03-09 20:48:02 +01:00
Marvin Pohl
ada48bc6e5 Bumped version to v1.3.0 2021-03-09 20:44:55 +01:00
Marvin Pohl
4e583a7756 Updated buildbot dependencies 2021-03-09 20:42:36 +01:00
Marvin Pohl
7a50c7a064 Fixed up unit test for buildbot 2.9 2021-03-09 20:37:00 +01:00
Marvin Pohl
56ef5a1d78 Merge branch 'update2.9' of https://github.com/mrstanwell/buildbot-gitea into mrstanwell-update2.9 2021-03-09 18:35:46 +01:00
Marvin Pohl
1444fee747 Bumped version to v1.2.4 2021-01-16 15:40:20 +01:00
Marvin Pohl
e0dc125ddd Allow git config to fail if the pr_source remote is not yet initialized. 2021-01-16 15:39:05 +01:00
mrstanwell
a47f7a512b Conform to code in GitLabStatusPush v2.9.4.
I don't fully understand the impact of these API changes, but without
them the status from buildbot upon a successful build was causing gitea
to mark commits with a yellow circle instead of a green checkmark.
Since GiteaStatusPush was based on GitLabStatusPush in the first place,
I tried making it look more like its ancestor -- and now the commit status
in gitea is working correctly.
2021-01-08 18:17:18 -06:00
mrstanwell
cd82223a81 Provide checkConfig(), to support buildbot 2.9.x.
Apparently, as of buildbot 2.9.x, [reporters need to provide their own
checkConfig() implementation when a service has custom args not supplied
to the superclass](https://github.com/buildbot/buildbot/pull/5571).  If
we don't do this, checkconfig will fail.
2021-01-05 13:53:26 -06:00
Marvin Pohl
b17a60beff Bumped version to v1.2.3 2020-10-27 02:02:01 +01:00
Marvin Pohl
c41cac7b56 Swapped order of hooks from oldest to newest to accomodate for fixed commit order. 2020-10-27 02:00:48 +01:00
mrstanwell
051a9e51ec Add commits to the changes list in reverse order.
The gitea webhook list of pushed commits is in order from newest to
oldest.  If commits are appended to the changes array and returned, the
last commit in the array will be the oldest commit in the push.
However, buildbot treats the last change as the *most* recent.  This
means that unless you use 'alwaysUseLatest=True' in your Git step, the
Git step will not check out the newest commit in the push.  If you
happen to be using 'shallow=True', this will actually cause the Git
update step to fail because only the newest commit is available in a
shallow checkout.

This update inserts each commit in the gitea webhook call at the
beginning of the array, which means buildbot sees them in chronological
order.  A Git step with 'shallow=True' will now succeed.
2020-10-27 01:52:07 +01:00
Marvin Pohl
15e7068043 Bumped version to v1.2.2 2020-06-01 14:55:19 +02:00
Benjamin Füldner
80f3aab446 Correct missing dollar sign to match end of line correctly in repo_name regex. 2020-05-27 14:12:42 +02:00
Marvin Pohl
8d2daa294f Bumped version to v1.2.1 2020-05-23 11:37:06 +02:00
Benjamin Füldner
27b2449f29
Remove .git from repo_name regex to get a valid repository name. (#8) 2020-05-15 16:54:01 +02:00
Marvin Pohl
2de8fa49e3 Updated documentation for Auth 2019-12-20 11:37:56 +01:00
Marvin Pohl
01e59b698b Bumped version to v.1.2.0 2019-12-20 11:31:24 +01:00
Marvin Pohl
4ea3571442 Moved GiteaAuth to buildbot.plugins.util since buildbot.plugins.auth does not exist. 2019-12-20 11:16:32 +01:00
Marvin Pohl
64c521f55b Added minimal unittests for GiteaAuth. 2019-12-20 10:44:52 +01:00
Marvin Pohl
479a029a5c Register GiteaAuth with the buildbout plugin system. 2019-12-20 10:44:35 +01:00
Marvin Pohl
a065597d57 Bring auth.py to PEP-8 standard. 2019-12-20 10:44:16 +01:00
Marvin Pohl
bc8f00a7e6 Merge branch 'gitea-auth-class' of https://github.com/youreadforme/buildbot-gitea into gitea-auth 2019-12-20 10:08:09 +01:00
Marvin Pohl
b8aa5dd740 Fixed test_step_source: git step now containing --progress in the command line 2019-12-20 10:06:31 +01:00
Tony Crowe
d0b9f76be6 shorter urljoin 2019-12-18 11:43:48 -07:00
Tony Crowe
b370626010 add GiteaAuth class and documentation 2019-12-17 15:36:07 -07:00
10 changed files with 811 additions and 560 deletions

View File

@ -1,9 +1,8 @@
# Buildbot Gitea Plugin
# Buildbot Transifex Plugin
[![PyPI version](https://badge.fury.io/py/buildbot-gitea.svg)](https://badge.fury.io/py/buildbot-gitea)
![GitHub](https://img.shields.io/github/license/lab132/buildbot-gitea)
[![Build Status](https://travis-ci.org/lab132/buildbot-gitea.svg?branch=master)](https://travis-ci.org/lab132/buildbot-gitea)
This plugin for buildbot adds integration support with gitea, featuring push hooks, commit status updates and a change source.
@ -123,9 +122,32 @@ The parameters are as follows:
| --- | --- |
| URL | The URL to the gitea instance. |
| `token` | Generate an access token in the profile you want the buildbot to impersonate. Make sure the account in gitea has access to the repositories. |
| `startDescription` | `Renderable` A short description when buildbot starts building on a change. Defaults to `Build started.` |
| `endDescription` | `Renderable` A short description when buildbot stops building on a change. Defaults to `Build done.` |
| `context` | `Renderable` The context is an identifier for this status, allowing to identify from which builder this came, defaults to `Interpolate('buildbot/%(prop:buildername)s')` |
| `context_pr` | `Renderable` The context message to use, when building on a pull request, allowing to identify from which builder this came, defaults to `Interpolate('buildbot/pull_request/%(prop:buildername)s')` |
| `warningAsSuccess` | Treat warnings as build as success to set in the build status of gitea. If false, warnings will be displayed as warnings. |
| `verbose` | Perform verbose output |
## Authentication
Gitea supports OAuth2 authentication so it is possible to have buildbot communicate to Gitea to authenticate the user.
`./master.cfg`
```py
from buildbot.plugins import util
c['www']['auth'] = util.GiteaAuth(
endpoint="https://your-gitea-host",
client_id='oauth2-client-id',
client_secret='oauth2-client-secret')
```
| Parameter | Value |
| --- | --- |
| `endpoint` | The URL to your Gitea app. Something like `https://gitea.example.com/` |
| `client_id` | The OAuth2 Client ID `GUID`, can be a `Secret`. |
| `client_secret` | The OAuth2 Client Secret provided, when creating the OAuth application in gitea. Can be a `Secret`. |
Resources:
+ [Gitea OAuth2 Provider documentation](https://docs.gitea.io/en-us/oauth2-provider/)
+ [Buildbot OAuth2 documentation](https://docs.buildbot.net/current/developer/cls-auth.html?highlight=oauth2#buildbot.www.oauth2.OAuth2Auth)

View File

@ -1,176 +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
import re
class GiteaStatusPush(http.HttpStatusPushBase):
name = "GiteaStatusPush"
neededDetails = dict(wantProperties=True)
ssh_url_match = re.compile(r"(ssh://)?[\w+\-\_]+@[\w\.\-\_]+:?(\d*/)?(?P<owner>[\w_\-\.]+)/(?P<repo_name>[\w_\-\.]+)(\.git)?")
@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={'Authorization': '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['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):
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 sha is None:
# No special revision for this, so ignore it
continue
if '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 '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
))

View File

@ -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, arg):
res = yield super(Gitea, self)._fetch(arg)
if self.build.hasProperty("pr_id"):
remote = yield self._dovccmd(
['config', 'remote.pr_source.url'], collectStdout=True)
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)

View File

@ -1,183 +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):
# repository must be in the form http://gitea/<owner>/<project>
TEST_REPO = u'http://gitea/buildbot/buildbot'
@defer.inlineCallbacks
def setUp(self):
self.setUpTestReactor()
# 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={'Authorization': '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.', '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.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.', 'context': 'buildbot/Builder0'})
build['complete'] = False
self.sp.buildStarted(("build", 20, "started"), build)
@defer.inlineCallbacks
def test_sshurl_noprops(self):
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.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.', '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.buildStarted(("build", 20, "started"), 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.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)

View File

@ -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', '-t',
'git@gitea.example.com:base/awesome_project.git', 'HEAD'])
+ 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()

View File

@ -2,13 +2,18 @@ import buildbot.www.change_hook as change_hook
from buildbot.test.fake.web import FakeRequest
from buildbot.test.fake.web import fakeMasterForHooks
from buildbot.test.util.misc import TestReactorMixin
from buildbot.secrets.manager import SecretManager
from buildbot.test.fake.secrets import FakeSecretStorage
from buildbot.process.properties import Secret
from twisted.internet import defer
from twisted.trial import unittest
from buildbot_gitea.webhook import GiteaHandler, _HEADER_EVENT_TYPE
from buildbot_gitea.webhook import GiteaHandler, _HEADER_EVENT_TYPE, _HEADER_SIGNATURE
giteaJsonPushPayload_Signature = 'b5feb0994ad24c209188d36a30cecfea86666aa9c65a419b068f73f91152e7bc'
giteaJsonPushPayload = rb"""
{
@ -111,6 +116,130 @@ giteaJsonPushPayload = rb"""
}
"""
giteaJsonPushModifiedFiles = rb"""
{
"secret": "pass",
"ref": "refs/heads/master",
"before": "92a8bf0e02b2146e6b35b71d6e08c376133b7fc9",
"after": "ea07c3148db428876add8b312256239275c395fb",
"compare_url": "https://git.example.com/Test/test/compare/92a8bf0e02b2146e6b35b71d6e08c376133b7fc9...ea07c3148db428876add8b312256239275c395fb",
"commits": [
{
"id": "ea07c3148db428876add8b312256239275c395fb",
"message": "test123\n",
"url": "https://git.example.com/Test/test/commit/ea07c3148db428876add8b312256239275c395fb",
"author": {
"name": "Test User",
"email": "Test@example.com",
"username": "Test"
},
"committer": {
"name": "Test User",
"email": "Test@example.com",
"username": "Test"
},
"verification": null,
"timestamp": "2021-03-09T20:12:19Z",
"added": [
"testfile2"
],
"removed": [
"testfile3"
],
"modified": [
"testfile1"
]
}
],
"head_commit": null,
"repository": {
"id": 29,
"owner": {
"id": 1,
"login": "Test",
"full_name": "Test User",
"email": "Test@example.com",
"avatar_url": "https://git.example.com/user/avatar/Test/-1",
"language": "en-US",
"is_admin": true,
"last_login": "2021-03-09T20:10:52Z",
"created": "2018-06-05T09:41:06Z",
"username": "Test"
},
"name": "test",
"full_name": "Test/test",
"description": "",
"empty": false,
"private": true,
"fork": false,
"template": false,
"parent": null,
"mirror": false,
"size": 17,
"html_url": "https://git.example.com/Test/test",
"ssh_url": "ssh://git@git.example.com/Test/test.git",
"clone_url": "https://git.example.com/Test/test.git",
"original_url": "",
"website": "",
"stars_count": 0,
"forks_count": 0,
"watchers_count": 1,
"open_issues_count": 0,
"open_pr_counter": 0,
"release_counter": 0,
"default_branch": "master",
"archived": false,
"created_at": "2019-03-03T17:26:23Z",
"updated_at": "2021-03-09T20:12:20Z",
"permissions": {
"admin": true,
"push": true,
"pull": true
},
"has_issues": true,
"internal_tracker": {
"enable_time_tracker": false,
"allow_only_contributors_to_track_time": true,
"enable_issue_dependencies": true
},
"has_wiki": true,
"has_pull_requests": true,
"has_projects": false,
"ignore_whitespace_conflicts": false,
"allow_merge_commits": true,
"allow_rebase": true,
"allow_rebase_explicit": true,
"allow_squash_merge": true,
"avatar_url": "",
"internal": false
},
"pusher": {
"id": 1,
"login": "Test",
"full_name": "Test User",
"email": "Test@example.com",
"avatar_url": "https://git.example.com/user/avatar/Test/-1",
"language": "en-US",
"is_admin": true,
"last_login": "2021-03-09T20:10:52Z",
"created": "2018-06-05T09:41:06Z",
"username": "Test"
},
"sender": {
"id": 1,
"login": "Test",
"full_name": "Test User",
"email": "Test@example.com",
"avatar_url": "https://git.example.com/user/avatar/Test/-1",
"language": "en-US",
"is_admin": true,
"last_login": "2021-03-09T20:10:52Z",
"created": "2018-06-05T09:41:06Z",
"username": "Test"
}
}
"""
giteaInvalidSecretPush = rb"""
{
"secret": "invalidSecret",
@ -195,6 +324,8 @@ giteaInvalidSecretPush = rb"""
}
"""
giteaJsonPullRequestPayload_Signature = '8685905c03fa521dd1eacfb84405195dbca2a08206c3a978a3656399f5dbe01a'
giteaJsonPullRequestPayload = rb"""
{
"secret": "test",
@ -370,6 +501,9 @@ giteaJsonPullRequestPayload = rb"""
}
"""
giteaJsonPullRequestPayloadNotMergeable_Signature = '5552a0cbcbb3fe6286681bc7846754929be0d3f27ccc32914e5fd3ce01f34632'
giteaJsonPullRequestPayloadNotMergeable = rb"""
{
"secret": "test",
@ -545,6 +679,7 @@ giteaJsonPullRequestPayloadNotMergeable = rb"""
}
"""
giteaJsonPullRequestPayloadMerged_Signature = '4d3b1045aea9aa5cce4f7270d549c11d212c55036d9c547d0c9327891d56bf97'
giteaJsonPullRequestPayloadMerged = rb"""
{
"secret": "test",
@ -720,6 +855,427 @@ giteaJsonPullRequestPayloadMerged = rb"""
}
"""
giteaJsonPullRequestFork = rb"""
{
"secret": "test",
"action": "opened",
"number": 4,
"pull_request": {
"id": 36,
"url": "https://git.example.com/testuser/webhook_test/pulls/4",
"number": 4,
"user": {
"id": 1,
"login": "testuser",
"full_name": "testuser name",
"email": "testuser@example.com",
"avatar_url": "https://git.example.com/user/avatar/testuser/-1",
"language": "en-US",
"is_admin": true,
"last_login": "2021-03-27T13:53:28Z",
"created": "2018-06-05T09:41:06Z",
"username": "testuser"
},
"title": "testfork",
"body": "Test PR",
"labels": [],
"milestone": null,
"assignee": null,
"assignees": null,
"state": "open",
"is_locked": false,
"comments": 0,
"html_url": "https://git.example.com/testuser/webhook_test/pulls/4",
"diff_url": "https://git.example.com/testuser/webhook_test/pulls/4.diff",
"patch_url": "https://git.example.com/testuser/webhook_test/pulls/4.patch",
"mergeable": true,
"merged": false,
"merged_at": null,
"merge_commit_sha": null,
"merged_by": null,
"base": {
"label": "master",
"ref": "master",
"sha": "449a5a8ca05607106b5ba41988c1a658a8949a18",
"repo_id": 20,
"repo": {
"id": 20,
"owner": {
"id": 1,
"login": "testuser",
"full_name": "testuser name",
"email": "testuser@example.com",
"avatar_url": "https://git.example.com/user/avatar/testuser/-1",
"language": "en-US",
"is_admin": true,
"last_login": "2021-03-27T13:53:28Z",
"created": "2018-06-05T09:41:06Z",
"username": "testuser"
},
"name": "webhook_test",
"full_name": "testuser/webhook_test",
"description": "",
"empty": false,
"private": true,
"fork": false,
"template": false,
"parent": null,
"mirror": false,
"size": 76,
"html_url": "https://git.example.com/testuser/webhook_test",
"ssh_url": "ssh://git@git.example.com/testuser/webhook_test.git",
"clone_url": "https://git.example.com/testuser/webhook_test.git",
"original_url": "",
"website": "",
"stars_count": 0,
"forks_count": 1,
"watchers_count": 1,
"open_issues_count": 0,
"open_pr_counter": 1,
"release_counter": 0,
"default_branch": "master",
"archived": false,
"created_at": "2018-09-04T10:45:23Z",
"updated_at": "2018-09-04T13:05:51Z",
"permissions": {
"admin": false,
"push": false,
"pull": false
},
"has_issues": true,
"internal_tracker": {
"enable_time_tracker": false,
"allow_only_contributors_to_track_time": true,
"enable_issue_dependencies": true
},
"has_wiki": true,
"has_pull_requests": true,
"has_projects": false,
"ignore_whitespace_conflicts": false,
"allow_merge_commits": true,
"allow_rebase": true,
"allow_rebase_explicit": true,
"allow_squash_merge": true,
"avatar_url": "",
"internal": false
}
},
"head": {
"label": "feature_branch",
"ref": "feature_branch",
"sha": "53e3075cbe468f14c2801d186d703e64b2adee12",
"repo_id": 34,
"repo": {
"id": 34,
"owner": {
"id": 14,
"login": "test_org",
"full_name": "",
"email": "",
"avatar_url": "https://git.example.com/user/avatar/test_org/-1",
"language": "",
"is_admin": false,
"last_login": "1970-01-01T00:00:00Z",
"created": "2018-09-27T11:35:41Z",
"username": "test_org"
},
"name": "webhook_test_fork",
"full_name": "test_org/webhook_test_fork",
"description": "",
"empty": false,
"private": true,
"fork": true,
"template": false,
"parent": {
"id": 20,
"owner": {
"id": 1,
"login": "testuser",
"full_name": "testuser name",
"email": "testuser@example.com",
"avatar_url": "https://git.example.com/user/avatar/testuser/-1",
"language": "en-US",
"is_admin": true,
"last_login": "2021-03-27T13:53:28Z",
"created": "2018-06-05T09:41:06Z",
"username": "testuser"
},
"name": "webhook_test",
"full_name": "testuser/webhook_test",
"description": "",
"empty": false,
"private": true,
"fork": false,
"template": false,
"parent": null,
"mirror": false,
"size": 76,
"html_url": "https://git.example.com/testuser/webhook_test",
"ssh_url": "ssh://git@git.example.com/testuser/webhook_test.git",
"clone_url": "https://git.example.com/testuser/webhook_test.git",
"original_url": "",
"website": "",
"stars_count": 0,
"forks_count": 1,
"watchers_count": 1,
"open_issues_count": 0,
"open_pr_counter": 2,
"release_counter": 0,
"default_branch": "master",
"archived": false,
"created_at": "2018-09-04T10:45:23Z",
"updated_at": "2018-09-04T13:05:51Z",
"permissions": {
"admin": false,
"push": false,
"pull": false
},
"has_issues": true,
"internal_tracker": {
"enable_time_tracker": false,
"allow_only_contributors_to_track_time": true,
"enable_issue_dependencies": true
},
"has_wiki": true,
"has_pull_requests": true,
"has_projects": false,
"ignore_whitespace_conflicts": false,
"allow_merge_commits": true,
"allow_rebase": true,
"allow_rebase_explicit": true,
"allow_squash_merge": true,
"avatar_url": "",
"internal": false
},
"mirror": false,
"size": 19,
"html_url": "https://git.example.com/test_org/webhook_test_fork",
"ssh_url": "ssh://git@git.example.com/test_org/webhook_test_fork.git",
"clone_url": "https://git.example.com/test_org/webhook_test_fork.git",
"original_url": "",
"website": "",
"stars_count": 0,
"forks_count": 0,
"watchers_count": 1,
"open_issues_count": 0,
"open_pr_counter": 0,
"release_counter": 0,
"default_branch": "master",
"archived": false,
"created_at": "2021-03-28T21:40:46Z",
"updated_at": "2021-03-28T21:41:01Z",
"permissions": {
"admin": false,
"push": false,
"pull": false
},
"has_issues": true,
"internal_tracker": {
"enable_time_tracker": false,
"allow_only_contributors_to_track_time": true,
"enable_issue_dependencies": true
},
"has_wiki": true,
"has_pull_requests": true,
"has_projects": true,
"ignore_whitespace_conflicts": false,
"allow_merge_commits": true,
"allow_rebase": true,
"allow_rebase_explicit": true,
"allow_squash_merge": true,
"avatar_url": "",
"internal": false
}
},
"merge_base": "449a5a8ca05607106b5ba41988c1a658a8949a18",
"due_date": null,
"created_at": "2021-03-28T21:41:24Z",
"updated_at": "2021-03-28T21:41:24Z",
"closed_at": null
},
"repository": {
"id": 20,
"owner": {
"id": 1,
"login": "testuser",
"full_name": "testuser name",
"email": "testuser@example.com",
"avatar_url": "https://git.example.com/user/avatar/testuser/-1",
"language": "en-US",
"is_admin": true,
"last_login": "2021-03-27T13:53:28Z",
"created": "2018-06-05T09:41:06Z",
"username": "testuser"
},
"name": "webhook_test",
"full_name": "testuser/webhook_test",
"description": "",
"empty": false,
"private": true,
"fork": false,
"template": false,
"parent": null,
"mirror": false,
"size": 76,
"html_url": "https://git.example.com/testuser/webhook_test",
"ssh_url": "ssh://git@git.example.com/testuser/webhook_test.git",
"clone_url": "https://git.example.com/testuser/webhook_test.git",
"original_url": "",
"website": "",
"stars_count": 0,
"forks_count": 1,
"watchers_count": 1,
"open_issues_count": 0,
"open_pr_counter": 2,
"release_counter": 0,
"default_branch": "master",
"archived": false,
"created_at": "2018-09-04T10:45:23Z",
"updated_at": "2018-09-04T13:05:51Z",
"permissions": {
"admin": true,
"push": true,
"pull": true
},
"has_issues": true,
"internal_tracker": {
"enable_time_tracker": false,
"allow_only_contributors_to_track_time": true,
"enable_issue_dependencies": true
},
"has_wiki": true,
"has_pull_requests": true,
"has_projects": false,
"ignore_whitespace_conflicts": false,
"allow_merge_commits": true,
"allow_rebase": true,
"allow_rebase_explicit": true,
"allow_squash_merge": true,
"avatar_url": "",
"internal": false
},
"sender": {
"id": 1,
"login": "testuser",
"full_name": "testuser name",
"email": "testuser@example.com",
"avatar_url": "https://git.example.com/user/avatar/testuser/-1",
"language": "en-US",
"is_admin": true,
"last_login": "2021-03-27T13:53:28Z",
"created": "2018-06-05T09:41:06Z",
"username": "testuser"
},
"review": null
}
"""
giteaJsonPushEmptyFiles = rb"""
{
"secret": "pass",
"ref": "refs/heads/develop",
"before": "2437bd7c6b0af7b8da570973c02f0cca07ec787d",
"after": "2437bd7c6b0af7b8da570973c02f0cca07ec787d",
"compare_url": "",
"commits": [
{
"id": "2437bd7c6b0af7b8da570973c02f0cca07ec787d",
"message": "snip",
"url": "snip/commit/2437bd7c6b0af7b8da570973c02f0cca07ec787d",
"author": {
"name": "snip",
"email": "snip",
"username": ""
},
"committer": {
"name": "snip",
"email": "snip",
"username": ""
},
"verification": null,
"timestamp": "0001-01-01T00:00:00Z",
"added": null,
"removed": null,
"modified": null
}
],
"head_commit": {
"id": "2437bd7c6b0af7b8da570973c02f0cca07ec787d",
"message": "snip",
"url": "snip/commit/2437bd7c6b0af7b8da570973c02f0cca07ec787d",
"author": {
"name": "snip",
"email": "snip",
"username": ""
},
"committer": {
"name": "snip",
"email": "snip",
"username": ""
},
"verification": null,
"timestamp": "0001-01-01T00:00:00Z",
"added": null,
"removed": null,
"modified": null
},
"repository": {
"id": "snip",
"owner": {"id":"snip","login":"snip","full_name":"snip","email":"snip","avatar_url":"snip","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-04T02:15:26+02:00","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"snip"},
"name": "snip",
"full_name": "snip",
"description": "snip",
"empty": false,
"private": true,
"fork": false,
"template": false,
"parent": null,
"mirror": false,
"size": 19106,
"html_url": "snip",
"ssh_url": "git@snip.git",
"clone_url": "snip.git",
"original_url": "",
"website": "",
"stars_count": 0,
"forks_count": 0,
"watchers_count": 5,
"open_issues_count": 33,
"open_pr_counter": 1,
"release_counter": 0,
"default_branch": "develop",
"archived": false,
"created_at": "2020-08-25T09:34:29+02:00",
"updated_at": "2022-01-19T15:55:11+01:00",
"permissions": {
"admin": false,
"push": false,
"pull": false
},
"has_issues": true,
"internal_tracker": {
"enable_time_tracker": false,
"allow_only_contributors_to_track_time": true,
"enable_issue_dependencies": true
},
"has_wiki": true,
"has_pull_requests": true,
"has_projects": false,
"ignore_whitespace_conflicts": false,
"allow_merge_commits": true,
"allow_rebase": true,
"allow_rebase_explicit": false,
"allow_squash_merge": true,
"default_merge_style": "merge",
"avatar_url": "",
"internal": false,
"mirror_interval": ""
},
"pusher": {"id":"snip","login":"snip","full_name":"snip","email":"snip","avatar_url":"snip","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-01-22T02:15:29+01:00","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"snip"},
"sender": {"id":"snip","login":"snip","full_name":"snip","email":"snip","avatar_url":"snip","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-01-22T02:15:29+01:00","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"snip"}
}
"""
class TestChangeHookGiteaPush(unittest.TestCase, TestReactorMixin):
def setUp(self):
@ -733,22 +1289,6 @@ class TestChangeHookGiteaPush(unittest.TestCase, TestReactorMixin):
change = self.changeHook.master.data.updates.changesAdded[0]
self.assertEqual(change['repository'], 'ssh://git@git.example.com/max/webhook_test.git')
self.assertEqual(
change["author"], "Max Mustermann <max@example.com>")
self.assertEqual(
change["revision"], '9d7157cc4a137b3e1dfe92750ccfb1bbad239f99')
self.assertEqual(
change["when_timestamp"],
1536063014)
self.assertEqual(
change["comments"], "TestBranch\n")
self.assertEqual(change["branch"], "feature-branch")
self.assertEqual(change[
"revlink"],
"https://git.example.com/max/webhook_test/commit/9d7157cc4a137b3e1dfe92750ccfb1bbad239f99")
change = self.changeHook.master.data.updates.changesAdded[1]
self.assertEqual(change['repository'], 'ssh://git@git.example.com/max/webhook_test.git')
self.assertEqual(
change["author"], "Max Mustermann <max@example.com>")
self.assertEqual(
@ -762,6 +1302,57 @@ class TestChangeHookGiteaPush(unittest.TestCase, TestReactorMixin):
self.assertEqual(change[
"revlink"],
"https://git.example.com/max/webhook_test/commit/ad7157cc4a137b3e1dfe92750ccfb1bbad239f9a")
change = self.changeHook.master.data.updates.changesAdded[1]
self.assertEqual(change['repository'], 'ssh://git@git.example.com/max/webhook_test.git')
self.assertEqual(
change["author"], "Max Mustermann <max@example.com>")
self.assertEqual(
change["revision"], '9d7157cc4a137b3e1dfe92750ccfb1bbad239f99')
self.assertEqual(
change["when_timestamp"],
1536063014)
self.assertEqual(
change["comments"], "TestBranch\n")
self.assertEqual(change["branch"], "feature-branch")
self.assertEqual(change[
"revlink"],
"https://git.example.com/max/webhook_test/commit/9d7157cc4a137b3e1dfe92750ccfb1bbad239f99")
def checkFileChanges(self, codebase=None):
self.assertEqual(len(self.changeHook.master.data.updates.changesAdded), 1)
change = self.changeHook.master.data.updates.changesAdded[0]
self.assertEqual(change['repository'], 'ssh://git@git.example.com/Test/test.git')
self.assertEqual(
change["author"], "Test User <Test@example.com>")
self.assertEqual(
change["revision"], 'ea07c3148db428876add8b312256239275c395fb')
self.assertEqual(
change["comments"], "test123\n")
self.assertEqual(change["branch"], "master")
self.assertEqual(change[
"revlink"],
"https://git.example.com/Test/test/commit/ea07c3148db428876add8b312256239275c395fb")
self.assertEqual(change["files"], ["testfile2", "testfile1", "testfile3"])
def checkNoFileChanges(self, codebase=None):
self.assertEqual(len(self.changeHook.master.data.updates.changesAdded), 1)
change = self.changeHook.master.data.updates.changesAdded[0]
self.assertEqual(change['repository'], 'git@snip.git')
self.assertEqual(
change["author"], "snip <snip>")
self.assertEqual(
change["revision"], '2437bd7c6b0af7b8da570973c02f0cca07ec787d')
self.assertEqual(
change["comments"], "snip")
self.assertEqual(change["branch"], "develop")
self.assertEqual(change[
"revlink"],
"snip/commit/2437bd7c6b0af7b8da570973c02f0cca07ec787d")
self.assertEqual(change["files"], [])
def checkChangesFromPullRequest(self, codebase=None):
self.assertEqual(len(self.changeHook.master.data.updates.changesAdded), 1)
@ -771,13 +1362,13 @@ class TestChangeHookGiteaPush(unittest.TestCase, TestReactorMixin):
self.assertEqual(
change["author"], "Max Mustermann <max@example.com>")
self.assertEqual(
change["revision"], '9d7157cc4a137b3e1dfe92750ccfb1bbad239f99')
change["revision"], '7c5de0796c409e7802abe759113d7fc37e0d6578')
self.assertEqual(
change["when_timestamp"],
1536063289)
self.assertEqual(
change["comments"], "PR#1: TestPR\n\n")
self.assertEqual(change["branch"], "feature-branch")
self.assertEqual(change["branch"], "master")
self.assertEqual(change[
"revlink"], "https://git.example.com/max/webhook_test/pulls/1")
properties = change["properties"]
@ -794,30 +1385,86 @@ class TestChangeHookGiteaPush(unittest.TestCase, TestReactorMixin):
self.assertEqual(properties["pr_id"], 8)
self.assertEqual(properties["pr_number"], 1)
def checkChangesFromPullRequestFork(self, codebase=None):
self.assertEqual(len(self.changeHook.master.data.updates.changesAdded), 1)
change = self.changeHook.master.data.updates.changesAdded[0]
self.assertEqual(change['repository'], 'ssh://git@git.example.com/testuser/webhook_test.git')
self.assertEqual(
change["author"], "testuser name <testuser@example.com>")
self.assertEqual(
change["revision"], '449a5a8ca05607106b5ba41988c1a658a8949a18')
self.assertEqual(change["branch"], "master")
self.assertEqual(change[
"revlink"], "https://git.example.com/testuser/webhook_test/pulls/4")
properties = change["properties"]
self.assertEqual(properties["base_branch"], "master")
self.assertEqual(properties["base_sha"], "449a5a8ca05607106b5ba41988c1a658a8949a18")
self.assertEqual(properties["base_repository"], "https://git.example.com/testuser/webhook_test.git")
self.assertEqual(properties["base_git_ssh_url"], "ssh://git@git.example.com/testuser/webhook_test.git")
self.assertEqual(properties["head_branch"], "feature_branch")
self.assertEqual(properties["head_sha"], "53e3075cbe468f14c2801d186d703e64b2adee12")
self.assertEqual(properties["head_repository"], "https://git.example.com/test_org/webhook_test_fork.git")
self.assertEqual(properties["head_git_ssh_url"], "ssh://git@git.example.com/test_org/webhook_test_fork.git")
self.assertEqual(properties["pr_id"], 36)
self.assertEqual(properties["pr_number"], 4)
@defer.inlineCallbacks
def testPushEvent(self):
self.request = FakeRequest(content=giteaJsonPushPayload)
self.request.uri = b'/change_hook/gitea'
self.request.method = b'POST'
self.request.received_headers[_HEADER_EVENT_TYPE] = b"push"
self.request.received_headers[_HEADER_SIGNATURE] = giteaJsonPushPayload_Signature
res = yield self.request.test_render(self.changeHook)
self.checkChangesFromPush(res)
@defer.inlineCallbacks
def testChangedFiles(self):
self.request = FakeRequest(content=giteaJsonPushModifiedFiles)
self.request.uri = b'/change_hook/gitea'
self.request.method = b'POST'
self.request.received_headers[_HEADER_EVENT_TYPE] = b"push"
res = yield self.request.test_render(self.changeHook)
self.checkFileChanges(res)
@defer.inlineCallbacks
def testNoChangedFiles(self):
self.request = FakeRequest(content=giteaJsonPushEmptyFiles)
self.request.uri = b'/change_hook/gitea'
self.request.method = b'POST'
self.request.received_headers[_HEADER_EVENT_TYPE] = b"push"
res = yield self.request.test_render(self.changeHook)
self.checkNoFileChanges(res)
@defer.inlineCallbacks
def testPullRequestEvent(self):
self.request = FakeRequest(content=giteaJsonPullRequestPayload)
self.request.uri = b'/change_hook/gitea'
self.request.method = b'POST'
self.request.received_headers[_HEADER_EVENT_TYPE] = b"pull_request"
self.request.received_headers[_HEADER_SIGNATURE] = giteaJsonPullRequestPayload_Signature
res = yield self.request.test_render(self.changeHook)
self.checkChangesFromPullRequest(res)
@defer.inlineCallbacks
def testPullRequestForkEvent(self):
self.request = FakeRequest(content=giteaJsonPullRequestFork)
self.request.uri = b'/change_hook/gitea'
self.request.method = b'POST'
self.request.received_headers[_HEADER_EVENT_TYPE] = b"pull_request"
res = yield self.request.test_render(self.changeHook)
self.checkChangesFromPullRequestFork(res)
@defer.inlineCallbacks
def testPullRequestNotMergeableEvent(self):
self.request = FakeRequest(content=giteaJsonPullRequestPayloadNotMergeable)
self.request.uri = b'/change_hook/gitea'
self.request.method = b'POST'
self.request.received_headers[_HEADER_EVENT_TYPE] = b"pull_request"
self.request.received_headers[_HEADER_SIGNATURE] = giteaJsonPullRequestPayloadNotMergeable_Signature
yield self.request.test_render(self.changeHook)
self.assertEqual(len(self.changeHook.master.data.updates.changesAdded), 0)
@ -827,6 +1474,7 @@ class TestChangeHookGiteaPush(unittest.TestCase, TestReactorMixin):
self.request.uri = b'/change_hook/gitea'
self.request.method = b'POST'
self.request.received_headers[_HEADER_EVENT_TYPE] = b"pull_request"
self.request.received_headers[_HEADER_SIGNATURE] = giteaJsonPullRequestPayloadMerged_Signature
yield self.request.test_render(self.changeHook)
self.assertEqual(len(self.changeHook.master.data.updates.changesAdded), 0)
@ -863,6 +1511,7 @@ class TestChangeHookGiteaPushOnlySingle(unittest.TestCase, TestReactorMixin):
self.request.uri = b'/change_hook/gitea'
self.request.method = b'POST'
self.request.received_headers[_HEADER_EVENT_TYPE] = b"push"
self.request.received_headers[_HEADER_SIGNATURE] = giteaJsonPushPayload_Signature
res = yield self.request.test_render(self.changeHook)
self.checkChangesFromPush(res)
@ -880,6 +1529,7 @@ class TestChangeHookGiteaSecretPhrase(unittest.TestCase, TestReactorMixin):
self.request.uri = b'/change_hook/gitea'
self.request.method = b'POST'
self.request.received_headers[_HEADER_EVENT_TYPE] = b"push"
self.request.received_headers[_HEADER_SIGNATURE] = giteaJsonPushPayload_Signature
yield self.request.test_render(self.changeHook)
self.assertEqual(len(self.changeHook.master.data.updates.changesAdded), 2)
@ -889,6 +1539,43 @@ class TestChangeHookGiteaSecretPhrase(unittest.TestCase, TestReactorMixin):
self.request.uri = b'/change_hook/gitea'
self.request.method = b'POST'
self.request.received_headers[_HEADER_EVENT_TYPE] = b"push"
self.request.received_headers[_HEADER_SIGNATURE] = giteaJsonPushPayload_Signature
yield self.request.test_render(self.changeHook)
self.assertEqual(len(self.changeHook.master.data.updates.changesAdded), 0)
class TestChangeHookGiteaSecretPhraseProvider(unittest.TestCase, TestReactorMixin):
def setUp(self):
self.setUpTestReactor()
self.master = fakeMasterForHooks(self)
self.changeHook = change_hook.ChangeHookResource(
dialects={'gitea': {"secret": Secret("token")}},
master=self.master)
fake_storage_service = FakeSecretStorage()
secret_service = SecretManager()
secret_service.services = [fake_storage_service]
secret_service.setServiceParent(self.master)
fake_storage_service.reconfigService(secretdict={"token": "test"})
@defer.inlineCallbacks
def testValidSecret(self):
self.request = FakeRequest(content=giteaJsonPushPayload)
self.request.uri = b'/change_hook/gitea'
self.request.method = b'POST'
self.request.received_headers[_HEADER_EVENT_TYPE] = b"push"
self.request.received_headers[_HEADER_SIGNATURE] = giteaJsonPushPayload_Signature
yield self.request.test_render(self.changeHook)
self.assertEqual(len(self.changeHook.master.data.updates.changesAdded), 2)
@defer.inlineCallbacks
def testInvalidSecret(self):
self.request = FakeRequest(content=giteaInvalidSecretPush)
self.request.uri = b'/change_hook/gitea'
self.request.method = b'POST'
self.request.received_headers[_HEADER_EVENT_TYPE] = b"push"
self.request.received_headers[_HEADER_SIGNATURE] = giteaJsonPushPayload_Signature
yield self.request.test_render(self.changeHook)
self.assertEqual(len(self.changeHook.master.data.updates.changesAdded), 0)
@ -921,6 +1608,7 @@ class TestChangeHookGiteaClass(unittest.TestCase, TestReactorMixin):
self.request.uri = b'/change_hook/gitea'
self.request.method = b'POST'
self.request.received_headers[_HEADER_EVENT_TYPE] = b'push'
self.request.received_headers[_HEADER_SIGNATURE] = giteaJsonPushPayload_Signature
yield self.request.test_render(self.changeHook)
self.checkChanges()
@ -931,6 +1619,7 @@ class TestChangeHookGiteaClass(unittest.TestCase, TestReactorMixin):
self.request.uri = b'/change_hook/gitea'
self.request.method = b'POST'
self.request.received_headers[_HEADER_EVENT_TYPE] = b'release'
self.request.received_headers[_HEADER_SIGNATURE] = giteaJsonPushPayload_Signature
yield self.request.test_render(self.changeHook)
self.checkChanges()

View File

@ -1,17 +1,25 @@
import base64
import json
import re
from buildbot.util import bytes2unicode
import hmac
import hashlib
from buildbot.process.properties import Properties
from buildbot.util import bytes2unicode, unicode2bytes
from buildbot.www.hooks.base import BaseHookHandler
from twisted.internet import defer
from twisted.python import log
from dateutil.parser import parse as dateparse
_HEADER_EVENT_TYPE = 'X-Gitea-Event'
_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 = []
@ -33,10 +41,14 @@ class GiteaHandler(BaseHookHandler):
commits = commits[:1]
for commit in commits:
files = []
for kind in ('added', 'modified', 'removed'):
files.extend(commit.get(kind, []) or [])
timestamp = dateparse(commit['timestamp'])
change = {
'author': '{} <{}>'.format(commit['author']['name'],
commit['author']['email']),
'files': files,
'comments': commit['message'],
'revision': commit['id'],
'when_timestamp': timestamp,
@ -53,10 +65,10 @@ class GiteaHandler(BaseHookHandler):
}
if codebase is not None:
change['codebase'] = codebase
changes.append(change)
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/.
@ -82,11 +94,11 @@ class GiteaHandler(BaseHookHandler):
pull_request['number'],
pull_request['title'],
pull_request['body']),
'revision': head['sha'],
'revision': base['sha'],
'when_timestamp': timestamp,
'branch': head['ref'],
'branch': base['ref'],
'revlink': pull_request['html_url'],
'repository': repository['ssh_url'],
'repository': base['repo']['ssh_url'],
'project': repository['full_name'],
'category': event_type,
'properties': {
@ -101,6 +113,8 @@ class GiteaHandler(BaseHookHandler):
'head_repo_id': head['repo_id'],
'head_repository': head['repo']['clone_url'],
'head_git_ssh_url': head['repo']['ssh_url'],
'head_owner': head['repo']['owner']['username'],
'head_reponame': head['repo']['name'],
'pr_id': pull_request['id'],
'pr_number': pull_request['number'],
'repository_name': repository['name'],
@ -111,47 +125,69 @@ 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
if isinstance(self.options, dict):
secret = self.options.get('secret')
try:
content = request.content.read()
payload = json.loads(bytes2unicode(content))
content_text = bytes2unicode(content)
payload = json.loads(content_text)
except Exception as exception:
raise ValueError('Error loading JSON: ' + str(exception))
if secret is not None and secret != payload['secret']:
raise ValueError('Invalid secret')
event_type = bytes2unicode(request.getHeader(_HEADER_EVENT_TYPE))
log.msg("Received event '{}' from gitea".format(event_type))
codebases = request.args.get('codebase', [None])
codebase = bytes2unicode(codebases[0])
if secret is not None:
p = Properties()
p.master = self.master
rendered_secret = yield p.render(secret)
signature = hmac.new(
unicode2bytes(rendered_secret),
unicode2bytes(content_text.strip()),
digestmod=hashlib.sha256)
header_signature = bytes2unicode(
request.getHeader(_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(payload.get(_EVENT_KEY), "None")
log.msg("Received event '{}' from transifex".format(event_type))
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

View File

@ -6,7 +6,7 @@ from setuptools import setup
with open("README.md", "r") as fh:
long_description = fh.read()
VERSION = "1.1.0"
VERSION = "1.7.2"
setup(name='buildbot-gitea',
version=VERSION,
@ -17,8 +17,8 @@ setup(name='buildbot-gitea',
long_description=long_description,
long_description_content_type="text/markdown",
packages=['buildbot_gitea'],
requires=[
"buildbot (>=2.0.0)"
install_requires=[
"buildbot>=3.0.0"
],
entry_points={
"buildbot.webhooks": [
@ -29,6 +29,9 @@ setup(name='buildbot-gitea',
],
"buildbot.reporters": [
"GiteaStatusPush = buildbot_gitea.reporter:GiteaStatusPush"
],
"buildbot.util": [
"GiteaAuth = buildbot_gitea.auth:GiteaAuth"
]
},
classifiers=[