##// END OF EJS Templates
git: use force fetch and update for target ref. This solves a case...
git: use force fetch and update for target ref. This solves a case when in PRs a target is force updated and is out of sync. Before we used a pull which --ff-only fails obviosly because two are out of sync. This change uses new logic that resets the target branch according to the source target branch allowing smooth merge simulation.

File last commit:

r2643:c2891b47 default
r2784:e8c62649 default
Show More
repo.py
356 lines | 11.2 KiB | text/x-python | PythonLexer
release: update copyright year to 2018
r2487 # Copyright (C) 2016-2018 RhodeCode GmbH
dan
events: add event system for RepoEvents
r375 #
# 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/
webhook: enable support of extra repo variables as replacement in template url.
r1761 import collections
dan
integrations: add integration support...
r411 import logging
integrations: parse pushed tags, and lightweight tags for git....
r2422 import datetime
dan
events: add serialization .to_dict() to events based on marshmallow
r379
dan
integrations: add integration support...
r411 from rhodecode.translation import lazy_ugettext
dan
events: fix bugs with serialization of repo/pr events and add tests for those cases
r389 from rhodecode.model.db import User, Repository, Session
dan
events: add serialization .to_dict() to events based on marshmallow
r379 from rhodecode.events.base import RhodecodeEvent
dan
events: change target to source repo for pull request events...
r514 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
dan
events: add serialization .to_dict() to events based on marshmallow
r379
Martin Bornhold
logging: Use __name__ when requesting a logger
r504 log = logging.getLogger(__name__)
dan
events: add event system for RepoEvents
r375
events: fixed missing construcors on user based events.
r1422
events: re-organizate events handling....
r1789 def _commits_as_dict(event, commit_ids, repos):
dan
events: change target to source repo for pull request events...
r514 """
Helper function to serialize commit_ids
events: re-organizate events handling....
r1789 :param event: class calling this method
dan
events: change target to source repo for pull request events...
r514 :param commit_ids: commits to get
:param repos: list of repos to check
"""
from rhodecode.lib.utils2 import extract_mentioned_users
slack: updated slack integration to use the attachements for nicer formatting.
r1467 from rhodecode.lib.helpers import (
urlify_commit_message, process_patterns, chop_at_smart)
events: expose permalink urls for different set of object....
r1788 from rhodecode.model.repo import RepoModel
dan
events: change target to source repo for pull request events...
r514
if not repos:
raise Exception('no repo defined')
if not isinstance(repos, (tuple, list)):
repos = [repos]
if not commit_ids:
return []
dan
events: send pushed commit ids in order
r782 needed_commits = list(commit_ids)
dan
events: change target to source repo for pull request events...
r514
commits = []
reviewers = []
for repo in repos:
if not needed_commits:
events: expose permalink urls for different set of object....
r1788 return commits # return early if we have the commits we need
dan
events: change target to source repo for pull request events...
r514
vcs_repo = repo.scm_instance(cache=False)
integrations: parse pushed tags, and lightweight tags for git....
r2422
dan
events: change target to source repo for pull request events...
r514 try:
dan
events: fix bug with _commits_as_dict which was returning only...
r795 # use copy of needed_commits since we modify it while iterating
for commit_id in list(needed_commits):
integrations: parse pushed tags, and lightweight tags for git....
r2422 if commit_id.startswith('tag=>'):
raw_id = commit_id[5:]
cs_data = {
'raw_id': commit_id, 'short_id': commit_id,
'branch': None,
'git_ref_change': 'tag_add',
'message': 'Added new tag {}'.format(raw_id),
'author': event.actor.full_contact,
'date': datetime.datetime.now(),
'refs': {
'branches': [],
'bookmarks': [],
'tags': []
}
}
commits.append(cs_data)
dan
events: change target to source repo for pull request events...
r514
integrations: parse pushed tags, and lightweight tags for git....
r2422 elif commit_id.startswith('delete_branch=>'):
raw_id = commit_id[15:]
cs_data = {
'raw_id': commit_id, 'short_id': commit_id,
'branch': None,
'git_ref_change': 'branch_delete',
'message': 'Deleted branch {}'.format(raw_id),
'author': event.actor.full_contact,
'date': datetime.datetime.now(),
'refs': {
'branches': [],
'bookmarks': [],
'tags': []
}
}
commits.append(cs_data)
else:
try:
cs = vcs_repo.get_changeset(commit_id)
except CommitDoesNotExistError:
continue # maybe its in next repo
cs_data = cs.__json__()
cs_data['refs'] = cs._get_refs()
dan
events: change target to source repo for pull request events...
r514 cs_data['mentions'] = extract_mentioned_users(cs_data['message'])
cs_data['reviewers'] = reviewers
events: expose permalink urls for different set of object....
r1788 cs_data['url'] = RepoModel().get_commit_url(
events: re-organizate events handling....
r1789 repo, cs_data['raw_id'], request=event.request)
events: expose permalink urls for different set of object....
r1788 cs_data['permalink_url'] = RepoModel().get_commit_url(
integrations: parse pushed tags, and lightweight tags for git....
r2422 repo, cs_data['raw_id'], request=event.request,
permalink=True)
dan
events: change target to source repo for pull request events...
r514 urlified_message, issues_data = process_patterns(
cs_data['message'], repo.repo_name)
cs_data['issues'] = issues_data
webhook: enable support of extra repo variables as replacement in template url.
r1761 cs_data['message_html'] = urlify_commit_message(
cs_data['message'], repo.repo_name)
cs_data['message_html_title'] = chop_at_smart(
cs_data['message'], '\n', suffix_if_chopped='...')
dan
events: change target to source repo for pull request events...
r514 commits.append(cs_data)
dan
events: send pushed commit ids in order
r782 needed_commits.remove(commit_id)
dan
events: change target to source repo for pull request events...
r514
integrations: parse pushed tags, and lightweight tags for git....
r2422 except Exception:
log.exception('Failed to extract commits data')
slack: updated slack integration to use the attachements for nicer formatting.
r1467 # we don't send any commits when crash happens, only full list
# matters we short circuit then.
dan
events: change target to source repo for pull request events...
r514 return []
missing_commits = set(commit_ids) - set(c['raw_id'] for c in commits)
if missing_commits:
events: improve the error message on missing event commits
r2643 log.error('Inconsistent repository state. '
'Missing commits: %s' % ', '.join(missing_commits))
dan
events: change target to source repo for pull request events...
r514
return commits
def _issues_as_dict(commits):
""" Helper function to serialize issues from commits """
issues = {}
for commit in commits:
for issue in commit['issues']:
issues[issue['id']] = issue
return issues
dan
events: add event system for RepoEvents
r375
events: fixed missing construcors on user based events.
r1422
dan
events: add event system for RepoEvents
r375 class RepoEvent(RhodecodeEvent):
"""
Base class for events acting on a repository.
:param repo: a :class:`Repository` instance
"""
dan
events: add serialization .to_dict() to events based on marshmallow
r379
dan
events: add event system for RepoEvents
r375 def __init__(self, repo):
dan
events: add serialization .to_dict() to events based on marshmallow
r379 super(RepoEvent, self).__init__()
dan
events: add event system for RepoEvents
r375 self.repo = repo
dan
integrations: add integration support...
r411 def as_dict(self):
from rhodecode.model.repo import RepoModel
data = super(RepoEvent, self).as_dict()
events: ported pylons part to pyramid....
r1959
webhook: enable support of extra repo variables as replacement in template url.
r1761 extra_fields = collections.OrderedDict()
for field in self.repo.extra_fields:
extra_fields[field.field_key] = field.field_value
dan
integrations: add integration support...
r411 data.update({
'repo': {
'repo_id': self.repo.repo_id,
'repo_name': self.repo.repo_name,
dan
events: add repo_type to repo events
r445 'repo_type': self.repo.repo_type,
events: re-organizate events handling....
r1789 'url': RepoModel().get_url(
self.repo, request=self.request),
'permalink_url': RepoModel().get_url(
self.repo, request=self.request, permalink=True),
webhook: enable support of extra repo variables as replacement in template url.
r1761 'extra_fields': extra_fields
dan
integrations: add integration support...
r411 }
})
return data
dan
events: add event system for RepoEvents
r375
class RepoPreCreateEvent(RepoEvent):
"""
An instance of this class is emitted as an :term:`event` before a repo is
created.
"""
name = 'repo-pre-create'
dan
integrations: add integration support...
r411 display_name = lazy_ugettext('repository pre create')
dan
events: add event system for RepoEvents
r375
dan
integrations: add integration support...
r411 class RepoCreateEvent(RepoEvent):
dan
events: add event system for RepoEvents
r375 """
An instance of this class is emitted as an :term:`event` whenever a repo is
created.
"""
dan
integrations: add integration support...
r411 name = 'repo-create'
display_name = lazy_ugettext('repository created')
dan
events: add event system for RepoEvents
r375
class RepoPreDeleteEvent(RepoEvent):
"""
An instance of this class is emitted as an :term:`event` whenever a repo is
created.
"""
name = 'repo-pre-delete'
dan
integrations: add integration support...
r411 display_name = lazy_ugettext('repository pre delete')
dan
events: add event system for RepoEvents
r375
dan
integrations: add integration support...
r411 class RepoDeleteEvent(RepoEvent):
dan
events: add event system for RepoEvents
r375 """
An instance of this class is emitted as an :term:`event` whenever a repo is
created.
"""
dan
integrations: add integration support...
r411 name = 'repo-delete'
display_name = lazy_ugettext('repository deleted')
dan
events: add event system for RepoEvents
r375
class RepoVCSEvent(RepoEvent):
"""
Base class for events triggered by the VCS
"""
def __init__(self, repo_name, extras):
self.repo = Repository.get_by_repo_name(repo_name)
if not self.repo:
raise Exception('repo by this name %s does not exist' % repo_name)
self.extras = extras
super(RepoVCSEvent, self).__init__(self.repo)
dan
events: add serialization .to_dict() to events based on marshmallow
r379 @property
dan
events: fix bugs with serialization of repo/pr events and add tests for those cases
r389 def actor(self):
dan
events: add serialization .to_dict() to events based on marshmallow
r379 if self.extras.get('username'):
dan
events: fix bugs with serialization of repo/pr events and add tests for those cases
r389 return User.get_by_username(self.extras['username'])
dan
events: add serialization .to_dict() to events based on marshmallow
r379
@property
dan
events: fix bugs with serialization of repo/pr events and add tests for those cases
r389 def actor_ip(self):
dan
events: add serialization .to_dict() to events based on marshmallow
r379 if self.extras.get('ip'):
dan
events: fix bugs with serialization of repo/pr events and add tests for those cases
r389 return self.extras['ip']
dan
events: add serialization .to_dict() to events based on marshmallow
r379
events: expose server_url for repo events.
r649 @property
def server_url(self):
if self.extras.get('server_url'):
return self.extras['server_url']
pyramid: ported pyramid routing for events
r2016 @property
def request(self):
return self.extras.get('request') or self.get_request()
dan
events: add event system for RepoEvents
r375
class RepoPrePullEvent(RepoVCSEvent):
"""
An instance of this class is emitted as an :term:`event` before commits
are pulled from a repo.
"""
name = 'repo-pre-pull'
dan
integrations: add integration support...
r411 display_name = lazy_ugettext('repository pre pull')
dan
events: add event system for RepoEvents
r375
class RepoPullEvent(RepoVCSEvent):
"""
An instance of this class is emitted as an :term:`event` after commits
are pulled from a repo.
"""
name = 'repo-pull'
dan
integrations: add integration support...
r411 display_name = lazy_ugettext('repository pull')
dan
events: add event system for RepoEvents
r375
class RepoPrePushEvent(RepoVCSEvent):
"""
An instance of this class is emitted as an :term:`event` before commits
are pushed to a repo.
"""
name = 'repo-pre-push'
dan
integrations: add integration support...
r411 display_name = lazy_ugettext('repository pre push')
dan
events: add event system for RepoEvents
r375
class RepoPushEvent(RepoVCSEvent):
"""
An instance of this class is emitted as an :term:`event` after commits
are pushed to a repo.
:param extras: (optional) dict of data from proxied VCS actions
"""
name = 'repo-push'
dan
integrations: add integration support...
r411 display_name = lazy_ugettext('repository push')
dan
events: add event system for RepoEvents
r375
def __init__(self, repo_name, pushed_commit_ids, extras):
super(RepoPushEvent, self).__init__(repo_name, extras)
self.pushed_commit_ids = pushed_commit_ids
integrations: parse pushed tags, and lightweight tags for git....
r2422 self.new_refs = extras.new_refs
dan
events: add event system for RepoEvents
r375
dan
integrations: add integration support...
r411 def as_dict(self):
data = super(RepoPushEvent, self).as_dict()
events: expose permalink urls for different set of object....
r1788
def branch_url(branch_name):
return '{}/changelog?branch={}'.format(
data['repo']['url'], branch_name)
dan
integrations: add integration support...
r411
integrations: parse pushed tags, and lightweight tags for git....
r2422 def tag_url(tag_name):
return '{}/files/{}/'.format(
data['repo']['url'], tag_name)
dan
events: change target to source repo for pull request events...
r514 commits = _commits_as_dict(
events: re-organizate events handling....
r1789 self, commit_ids=self.pushed_commit_ids, repos=[self.repo])
dan
events: use branch from previous commit for repo push event commits...
r815
last_branch = None
for commit in reversed(commits):
commit['branch'] = commit['branch'] or last_branch
last_branch = commit['branch']
dan
events: change target to source repo for pull request events...
r514 issues = _issues_as_dict(commits)
dan
integrations: add integration support...
r411
integrations: parse pushed tags, and lightweight tags for git....
r2422 branches = set()
tags = set()
for commit in commits:
if commit['refs']['tags']:
for tag in commit['refs']['tags']:
tags.add(tag)
if commit['branch']:
branches.add(commit['branch'])
# maybe we have branches in new_refs ?
try:
branches = branches.union(set(self.new_refs['branches']))
except Exception:
pass
dan
integrations: add integration support...
r411 branches = [
{
'name': branch,
events: expose permalink urls for different set of object....
r1788 'url': branch_url(branch)
dan
integrations: add integration support...
r411 }
for branch in branches
]
integrations: parse pushed tags, and lightweight tags for git....
r2422 # maybe we have branches in new_refs ?
try:
tags = tags.union(set(self.new_refs['tags']))
except Exception:
pass
tags = [
{
'name': tag,
'url': tag_url(tag)
}
for tag in tags
]
dan
integrations: add integration support...
r411 data['push'] = {
'commits': commits,
'issues': issues,
'branches': branches,
integrations: parse pushed tags, and lightweight tags for git....
r2422 'tags': tags,
dan
integrations: add integration support...
r411 }
Martin Bornhold
logging: Use __name__ when requesting a logger
r504 return data