##// END OF EJS Templates
feat(configs): deprecared old hooks protocol and ssh wrapper....
feat(configs): deprecared old hooks protocol and ssh wrapper. New defaults are now set on v2 keys, so previous installation are automatically set to new keys. Fallback mode is still available.

File last commit:

r5123:1d3bc909 default
r5496:cab50adf default
Show More
base.py
300 lines | 10.7 KiB | text/x-python | PythonLexer
copyrights: updated for 2023
r5088 # Copyright (C) 2012-2023 RhodeCode GmbH
dan
integrations: add integration support...
r411 #
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# 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 Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
dan
integrations: refactor/cleanup + features, fixes #4181...
r731 import colander
webhook: abstract webhook handler to base for easier re-usage.
r2585 import string
import collections
import logging
integrations: restructure code and added better coverage.
r5123
integrations: implement retry to HTTP[S] calls for integrations.
r3110 import requests
integrations: fixed code for python3
r5064 import urllib.request
import urllib.parse
import urllib.error
integrations: implement retry to HTTP[S] calls for integrations.
r3110 from requests.adapters import HTTPAdapter
integrations: restructure code and added better coverage.
r5123 from requests.packages.urllib3.util import Retry
dan
integrations: added safe renderers with detailed traceback information.
r2646
from mako import exceptions
integrations: restructure code and added better coverage.
r5123
from rhodecode.lib.str_utils import safe_str
dan
integrations: add integration support...
r411
dan
integrations: added safe renderers with detailed traceback information.
r2646
webhook: abstract webhook handler to base for easier re-usage.
r2585 log = logging.getLogger(__name__)
dan
integrations: add integration support...
r411
webhook: quote URL variables to prevent url errors with special chars like # in pr title.
r3477 class UrlTmpl(string.Template):
def safe_substitute(self, **kws):
# url encode the kw for usage in url
python3: fix urllib usage
r4914 kws = {k: urllib.parse.quote(safe_str(v)) for k, v in kws.items()}
modernize: updates for python3
r5095 return super().safe_substitute(**kws)
webhook: quote URL variables to prevent url errors with special chars like # in pr title.
r3477
dan
integrations: add integration support...
r411 class IntegrationTypeBase(object):
""" Base class for IntegrationType plugins """
integrations: expose EE integrations as dummy objects to show...
r2138 is_dummy = False
dan
integrations: refactor/cleanup + features, fixes #4181...
r731 description = ''
integrations: use classmethod for icon extraction for easier code readability.
r2576
@classmethod
def icon(cls):
return '''
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://setwww.inkscape.org/namespaces/inkscape"
viewBox="0 -256 1792 1792"
id="svg3025"
version="1.1"
inkscape:version="0.48.3.1 r9886"
width="100%"
height="100%"
sodipodi:docname="cog_font_awesome.svg">
<metadata
id="metadata3035">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3033" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="640"
inkscape:window-height="480"
id="namedview3031"
showgrid="false"
inkscape:zoom="0.13169643"
inkscape:cx="896"
inkscape:cy="896"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="svg3025" />
<g
transform="matrix(1,0,0,-1,121.49153,1285.4237)"
id="g3027">
<path
d="m 1024,640 q 0,106 -75,181 -75,75 -181,75 -106,0 -181,-75 -75,-75 -75,-181 0,-106 75,-181 75,-75 181,-75 106,0 181,75 75,75 75,181 z m 512,109 V 527 q 0,-12 -8,-23 -8,-11 -20,-13 l -185,-28 q -19,-54 -39,-91 35,-50 107,-138 10,-12 10,-25 0,-13 -9,-23 -27,-37 -99,-108 -72,-71 -94,-71 -12,0 -26,9 l -138,108 q -44,-23 -91,-38 -16,-136 -29,-186 -7,-28 -36,-28 H 657 q -14,0 -24.5,8.5 Q 622,-111 621,-98 L 593,86 q -49,16 -90,37 L 362,16 Q 352,7 337,7 323,7 312,18 186,132 147,186 q -7,10 -7,23 0,12 8,23 15,21 51,66.5 36,45.5 54,70.5 -27,50 -41,99 L 29,495 Q 16,497 8,507.5 0,518 0,531 v 222 q 0,12 8,23 8,11 19,13 l 186,28 q 14,46 39,92 -40,57 -107,138 -10,12 -10,24 0,10 9,23 26,36 98.5,107.5 72.5,71.5 94.5,71.5 13,0 26,-10 l 138,-107 q 44,23 91,38 16,136 29,186 7,28 36,28 h 222 q 14,0 24.5,-8.5 Q 914,1391 915,1378 l 28,-184 q 49,-16 90,-37 l 142,107 q 9,9 24,9 13,0 25,-10 129,-119 165,-170 7,-8 7,-22 0,-12 -8,-23 -15,-21 -51,-66.5 -36,-45.5 -54,-70.5 26,-50 41,-98 l 183,-28 q 13,-2 21,-12.5 8,-10.5 8,-23.5 z"
id="path3029"
inkscape:connector-curvature="0"
style="fill:currentColor" />
</g>
</svg>
'''
dan
integrations: refactor/cleanup + features, fixes #4181...
r731
dan
integrations: add integration support...
r411 def __init__(self, settings):
"""
:param settings: dict of settings to be used for the integration
"""
self.settings = settings
dan
forms: add deform for integration settings forms
r518 def settings_schema(self):
dan
integrations: add integration support...
r411 """
A colander schema of settings for the integration type
"""
dan
integrations: refactor/cleanup + features, fixes #4181...
r731 return colander.Schema()
integrations: expose EE integrations as dummy objects to show...
r2138
events: added support for pull-request-comment and commit-comment events....
r4314 def event_enabled(self, event):
"""
Checks if submitted event is enabled based on the plugin settings
:param event:
:return: bool
"""
api: added proper full permission flush on API calls when creating repos and repo groups....
r4697 allowed_events = self.settings.get('events') or []
events: added support for pull-request-comment and commit-comment events....
r4314 if event.name not in allowed_events:
log.debug('event ignored: %r event %s not in allowed set of events %s',
event, event.name, allowed_events)
return False
return True
integrations: expose EE integrations as dummy objects to show...
r2138
class EEIntegration(IntegrationTypeBase):
description = 'Integration available in RhodeCode EE edition.'
is_dummy = True
def __init__(self, name, key, settings=None):
self.display_name = name
self.key = key
integrations: extract get_auth to common shared code.
r2577 super(EEIntegration, self).__init__(settings)
integrations: expose some common methods for web based calls of integrations.
r2580 # Helpers #
dan
integrations: added branch_head into URL variables. This allow triggering more explicit...
r2864 # updating this required to update the `common_vars` as well.
webhook: use textarea and format url vars better for webhook integration....
r2584 WEBHOOK_URL_VARS = [
events: added support for pull-request-comment and commit-comment events....
r4314 # GENERAL
('General', [
('event_name', 'Unique name of the event type, e.g pullrequest-update'),
('repo_name', 'Full name of the repository'),
('repo_type', 'VCS type of repository'),
('repo_id', 'Unique id of repository'),
('repo_url', 'Repository url'),
]
),
integrations: expose some common methods for web based calls of integrations.
r2580 # extra repo fields
events: added support for pull-request-comment and commit-comment events....
r4314 ('Repository', [
('extra:<extra_key_name>', 'Extra repo variables, read from its settings.'),
]
),
integrations: expose some common methods for web based calls of integrations.
r2580 # special attrs below that we handle, using multi-call
events: added support for pull-request-comment and commit-comment events....
r4314 ('Commit push - Multicalls', [
('branch', 'Name of each branch submitted, if any.'),
('branch_head', 'Head ID of pushed branch (full sha of last commit), if any.'),
('commit_id', 'ID (full sha) of each commit submitted, if any.'),
]
),
integrations: expose some common methods for web based calls of integrations.
r2580 # pr events vars
events: added support for pull-request-comment and commit-comment events....
r4314 ('Pull request', [
('pull_request_id', 'Unique ID of the pull request.'),
('pull_request_title', 'Title of the pull request.'),
('pull_request_url', 'Pull request url.'),
('pull_request_shadow_url', 'Pull request shadow repo clone url.'),
('pull_request_commits_uid', 'Calculated UID of all commits inside the PR. '
'Changes after PR update'),
]
),
# commit comment event vars
('Commit comment', [
('commit_comment_id', 'Unique ID of the comment made on a commit.'),
('commit_comment_text', 'Text of commit comment.'),
('commit_comment_type', 'Type of comment, e.g note/todo.'),
integrations: expose some common methods for web based calls of integrations.
r2580
events: added support for pull-request-comment and commit-comment events....
r4314 ('commit_comment_f_path', 'Optionally path of file for inline comments.'),
('commit_comment_line_no', 'Line number of the file: eg o10, or n200'),
('commit_comment_commit_id', 'Commit id that comment was left at.'),
('commit_comment_commit_branch', 'Commit branch that comment was left at'),
('commit_comment_commit_message', 'Commit message that comment was left at'),
]
),
integrations: expose some common methods for web based calls of integrations.
r2580 # user who triggers the call
events: added support for pull-request-comment and commit-comment events....
r4314 ('Caller', [
('username', 'User who triggered the call.'),
('user_id', 'User id who triggered the call.'),
]
),
integrations: expose some common methods for web based calls of integrations.
r2580 ]
webhook: use textarea and format url vars better for webhook integration....
r2584 # common vars for url template used for CI plugins. Shared with webhook
CI_URL_VARS = WEBHOOK_URL_VARS
integrations: extract get_auth to common shared code.
r2577
dan
integrations: use a common logic for parsing the commits branches inside the integrations that require it....
r2644 class CommitParsingDataHandler(object):
def aggregate_branch_data(self, branches, commits):
branch_data = collections.OrderedDict()
for obj in branches:
branch_data[obj['name']] = obj
branches_commits = collections.OrderedDict()
for commit in commits:
if commit.get('git_ref_change'):
# special case for GIT that allows creating tags,
# deleting branches without associated commit
continue
commit_branch = commit['branch']
if commit_branch not in branches_commits:
_branch = branch_data[commit_branch] \
if commit_branch else commit_branch
branch_commits = {'branch': _branch,
dan
integrations: added branch_head into URL variables. This allow triggering more explicit...
r2864 'branch_head': '',
dan
integrations: use a common logic for parsing the commits branches inside the integrations that require it....
r2644 'commits': []}
branches_commits[commit_branch] = branch_commits
branch_commits = branches_commits[commit_branch]
branch_commits['commits'].append(commit)
dan
integrations: added branch_head into URL variables. This allow triggering more explicit...
r2864 branch_commits['branch_head'] = commit['raw_id']
dan
integrations: use a common logic for parsing the commits branches inside the integrations that require it....
r2644 return branches_commits
integrations: extract get_auth to common shared code.
r2577 def get_auth(settings):
from requests.auth import HTTPBasicAuth
username = settings.get('username')
password = settings.get('password')
if username and password:
return HTTPBasicAuth(username, password)
return None
integrations: expose some common methods for web based calls of integrations.
r2580
webhook: abstract webhook handler to base for easier re-usage.
r2585 def get_web_token(settings):
return settings['secret_token']
integrations: expose some common methods for web based calls of integrations.
r2580 def get_url_vars(url_vars):
events: added support for pull-request-comment and commit-comment events....
r4314 items = []
for section, section_items in url_vars:
modernize: updates for python3
r5095 items.append(f'\n*{section}*')
events: added support for pull-request-comment and commit-comment events....
r4314 for key, explanation in section_items:
items.append(' {} - {}'.format('${' + key + '}', explanation))
return '\n'.join(items)
dan
integrations: added safe renderers with detailed traceback information.
r2646
def render_with_traceback(template, *args, **kwargs):
try:
return template.render(*args, **kwargs)
except Exception:
log.error(exceptions.text_error_template().render())
raise
integrations: implement retry to HTTP[S] calls for integrations.
r3110
STATUS_400 = (400, 401, 403)
STATUS_500 = (500, 502, 504)
def requests_retry_call(
retries=3, backoff_factor=0.3, status_forcelist=STATUS_400+STATUS_500,
session=None):
"""
session = requests_retry_session()
response = session.get('http://example.com')
:param retries:
:param backoff_factor:
:param status_forcelist:
:param session:
"""
session = session or requests.Session()
retry = Retry(
total=retries,
read=retries,
connect=retries,
backoff_factor=backoff_factor,
status_forcelist=status_forcelist,
)
adapter = HTTPAdapter(max_retries=retry)
session.mount('http://', adapter)
session.mount('https://', adapter)
return session