|
|
# Copyright (C) 2012-2024 RhodeCode GmbH
|
|
|
#
|
|
|
# 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/
|
|
|
|
|
|
import logging
|
|
|
|
|
|
from rhodecode import events
|
|
|
from rhodecode.integrations.types.base import CommitParsingDataHandler, UrlTmpl
|
|
|
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
class WebhookDataHandler(CommitParsingDataHandler):
|
|
|
name = 'webhook'
|
|
|
|
|
|
def __init__(self, template_url, headers):
|
|
|
self.template_url = template_url
|
|
|
self.headers = headers
|
|
|
|
|
|
def get_base_parsed_template(self, data):
|
|
|
"""
|
|
|
initially parses the passed in template with some common variables
|
|
|
available on ALL calls
|
|
|
"""
|
|
|
# note: make sure to update the `WEBHOOK_URL_VARS` if this changes
|
|
|
common_vars = {
|
|
|
'repo_name': data['repo']['repo_name'],
|
|
|
'repo_type': data['repo']['repo_type'],
|
|
|
'repo_id': data['repo']['repo_id'],
|
|
|
'repo_url': data['repo']['url'],
|
|
|
'username': data['actor']['username'],
|
|
|
'user_id': data['actor']['user_id'],
|
|
|
'event_name': data['name']
|
|
|
}
|
|
|
|
|
|
extra_vars = {}
|
|
|
for extra_key, extra_val in data['repo']['extra_fields'].items():
|
|
|
extra_vars[f'extra__{extra_key}'] = extra_val
|
|
|
common_vars.update(extra_vars)
|
|
|
|
|
|
template_url = self.template_url.replace('${extra:', '${extra__')
|
|
|
for k, v in common_vars.items():
|
|
|
template_url = UrlTmpl(template_url).safe_substitute(**{k: v})
|
|
|
return template_url
|
|
|
|
|
|
def repo_push_event_handler(self, event, data):
|
|
|
url = self.get_base_parsed_template(data)
|
|
|
url_calls = []
|
|
|
|
|
|
branches_commits = self.aggregate_branch_data(
|
|
|
data['push']['branches'], data['push']['commits'])
|
|
|
if '${branch}' in url or '${branch_head}' in url or '${commit_id}' in url:
|
|
|
# call it multiple times, for each branch if used in variables
|
|
|
for branch, commit_ids in branches_commits.items():
|
|
|
branch_url = UrlTmpl(url).safe_substitute(branch=branch)
|
|
|
|
|
|
if '${branch_head}' in branch_url:
|
|
|
# last commit in the aggregate is the head of the branch
|
|
|
branch_head = commit_ids['branch_head']
|
|
|
branch_url = UrlTmpl(branch_url).safe_substitute(branch_head=branch_head)
|
|
|
|
|
|
# call further down for each commit if used
|
|
|
if '${commit_id}' in branch_url:
|
|
|
for commit_data in commit_ids['commits']:
|
|
|
commit_id = commit_data['raw_id']
|
|
|
commit_url = UrlTmpl(branch_url).safe_substitute(commit_id=commit_id)
|
|
|
# register per-commit call
|
|
|
log.debug(
|
|
|
'register %s call(%s) to url %s',
|
|
|
self.name, event, commit_url)
|
|
|
url_calls.append(
|
|
|
(commit_url, self.headers, data))
|
|
|
|
|
|
else:
|
|
|
# register per-branch call
|
|
|
log.debug('register %s call(%s) to url %s',
|
|
|
self.name, event, branch_url)
|
|
|
url_calls.append((branch_url, self.headers, data))
|
|
|
|
|
|
else:
|
|
|
log.debug('register %s call(%s) to url %s', self.name, event, url)
|
|
|
url_calls.append((url, self.headers, data))
|
|
|
|
|
|
return url_calls
|
|
|
|
|
|
def repo_commit_comment_handler(self, event, data):
|
|
|
url = self.get_base_parsed_template(data)
|
|
|
log.debug('register %s call(%s) to url %s', self.name, event, url)
|
|
|
comment_vars = [
|
|
|
('commit_comment_id', data['comment']['comment_id']),
|
|
|
('commit_comment_text', data['comment']['comment_text']),
|
|
|
('commit_comment_type', data['comment']['comment_type']),
|
|
|
|
|
|
('commit_comment_f_path', data['comment']['comment_f_path']),
|
|
|
('commit_comment_line_no', data['comment']['comment_line_no']),
|
|
|
|
|
|
('commit_comment_commit_id', data['commit']['commit_id']),
|
|
|
('commit_comment_commit_branch', data['commit']['commit_branch']),
|
|
|
('commit_comment_commit_message', data['commit']['commit_message']),
|
|
|
]
|
|
|
for k, v in comment_vars:
|
|
|
url = UrlTmpl(url).safe_substitute(**{k: v})
|
|
|
|
|
|
return [(url, self.headers, data)]
|
|
|
|
|
|
def repo_commit_comment_edit_handler(self, event, data):
|
|
|
url = self.get_base_parsed_template(data)
|
|
|
log.debug('register %s call(%s) to url %s', self.name, event, url)
|
|
|
comment_vars = [
|
|
|
('commit_comment_id', data['comment']['comment_id']),
|
|
|
('commit_comment_text', data['comment']['comment_text']),
|
|
|
('commit_comment_type', data['comment']['comment_type']),
|
|
|
|
|
|
('commit_comment_f_path', data['comment']['comment_f_path']),
|
|
|
('commit_comment_line_no', data['comment']['comment_line_no']),
|
|
|
|
|
|
('commit_comment_commit_id', data['commit']['commit_id']),
|
|
|
('commit_comment_commit_branch', data['commit']['commit_branch']),
|
|
|
('commit_comment_commit_message', data['commit']['commit_message']),
|
|
|
]
|
|
|
for k, v in comment_vars:
|
|
|
url = UrlTmpl(url).safe_substitute(**{k: v})
|
|
|
|
|
|
return [(url, self.headers, data)]
|
|
|
|
|
|
def repo_create_event_handler(self, event, data):
|
|
|
url = self.get_base_parsed_template(data)
|
|
|
log.debug('register %s call(%s) to url %s', self.name, event, url)
|
|
|
return [(url, self.headers, data)]
|
|
|
|
|
|
def pull_request_event_handler(self, event, data):
|
|
|
url = self.get_base_parsed_template(data)
|
|
|
log.debug('register %s call(%s) to url %s', self.name, event, url)
|
|
|
pr_vars = [
|
|
|
('pull_request_id', data['pullrequest']['pull_request_id']),
|
|
|
('pull_request_title', data['pullrequest']['title']),
|
|
|
('pull_request_url', data['pullrequest']['url']),
|
|
|
('pull_request_shadow_url', data['pullrequest']['shadow_url']),
|
|
|
('pull_request_commits_uid', data['pullrequest']['commits_uid']),
|
|
|
]
|
|
|
for k, v in pr_vars:
|
|
|
url = UrlTmpl(url).safe_substitute(**{k: v})
|
|
|
|
|
|
return [(url, self.headers, data)]
|
|
|
|
|
|
def __call__(self, event, data):
|
|
|
|
|
|
if isinstance(event, events.RepoPushEvent):
|
|
|
return self.repo_push_event_handler(event, data)
|
|
|
elif isinstance(event, events.RepoCreateEvent):
|
|
|
return self.repo_create_event_handler(event, data)
|
|
|
elif isinstance(event, events.RepoCommitCommentEvent):
|
|
|
return self.repo_commit_comment_handler(event, data)
|
|
|
elif isinstance(event, events.RepoCommitCommentEditEvent):
|
|
|
return self.repo_commit_comment_edit_handler(event, data)
|
|
|
elif isinstance(event, events.PullRequestEvent):
|
|
|
return self.pull_request_event_handler(event, data)
|
|
|
else:
|
|
|
raise ValueError(
|
|
|
f'event type `{event.__class__}` has no handler defined')
|
|
|
|