[distgit/pagure] hotfix the default hook to clean the PR merge status async
This is necessary because of the way our dist-git is deployed, the git hook only have a read-only access to the database so they can't reset the cached merge status of the open PRs in the same process so we need to do this via an async process which is basically what this hotfix does. Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>
This commit is contained in:
parent
7e76690649
commit
89fce190b9
2 changed files with 368 additions and 0 deletions
358
roles/distgit/pagure/files/hotfix-20190227-hooks-default.py
Normal file
358
roles/distgit/pagure/files/hotfix-20190227-hooks-default.py
Normal file
|
@ -0,0 +1,358 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
(c) 2016-2017 - Copyright Red Hat Inc
|
||||
|
||||
Authors:
|
||||
Pierre-Yves Chibon <pingou@pingoured.fr>
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, print_function, absolute_import
|
||||
|
||||
import logging
|
||||
|
||||
import pygit2
|
||||
import six
|
||||
|
||||
import pagure.config
|
||||
import pagure.exceptions
|
||||
import pagure.lib.query
|
||||
import pagure.lib.tasks
|
||||
import pagure.lib.tasks_services
|
||||
import pagure.utils
|
||||
from pagure.hooks import BaseHook, BaseRunner
|
||||
|
||||
|
||||
_config = pagure.config.reload_config()
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def send_fedmsg_notifications(project, topic, msg):
|
||||
""" If the user or admin asked for fedmsg notifications on commit, this will
|
||||
do it.
|
||||
"""
|
||||
|
||||
fedmsg_hook = pagure.lib.plugins.get_plugin("Fedmsg")
|
||||
fedmsg_hook.db_object()
|
||||
|
||||
always_fedmsg = _config.get("ALWAYS_FEDMSG_ON_COMMITS") or None
|
||||
|
||||
# Send fedmsg and fedora-messaging notification
|
||||
# (if fedmsg and fedora-messaging are there and set-up)
|
||||
if always_fedmsg or (project.fedmsg_hook and project.fedmsg_hook.active):
|
||||
if _config.get("FEDMSG_NOTIFICATIONS", True):
|
||||
try:
|
||||
print(" - to fedmsg")
|
||||
import fedmsg
|
||||
|
||||
config = fedmsg.config.load_config([], None)
|
||||
config["active"] = True
|
||||
config["endpoints"]["relay_inbound"] = config["relay_inbound"]
|
||||
fedmsg.init(name="relay_inbound", **config)
|
||||
|
||||
pagure.lib.notify.fedmsg_publish(topic=topic, msg=msg)
|
||||
except Exception:
|
||||
_log.exception(
|
||||
"Error sending fedmsg notifications on commit push"
|
||||
)
|
||||
|
||||
if _config.get("FEDORA_MESSAGING_NOTIFICATIONS", False):
|
||||
try:
|
||||
print(" - to fedora-message")
|
||||
pagure.lib.notify.fedora_messaging_publish(topic, msg)
|
||||
except Exception:
|
||||
_log.exception(
|
||||
"Error sending fedora-messaging notifications on "
|
||||
"commit push"
|
||||
)
|
||||
|
||||
|
||||
def send_stomp_notifications(project, topic, msg):
|
||||
""" If the user or admin asked for stomp notifications on commit, this will
|
||||
do it.
|
||||
"""
|
||||
always_stomp = _config.get("ALWAYS_STOMP_ON_COMMITS") or None
|
||||
# Send stomp notification (if stomp is there and set-up)
|
||||
if always_stomp or (project.fedmsg_hook and project.fedmsg_hook.active):
|
||||
try:
|
||||
print(" - to stomp")
|
||||
pagure.lib.notify.stomp_publish(topic, msg)
|
||||
except Exception:
|
||||
_log.exception("Error sending stomp notifications on commit push")
|
||||
|
||||
|
||||
def send_mqtt_notifications(project, topic, msg):
|
||||
""" If the user or admin asked for mqtt notifications on commit, this will
|
||||
do it.
|
||||
"""
|
||||
always_mqtt = _config.get("ALWAYS_MQTT_ON_COMMITS") or None
|
||||
# Send mqtt notification (if mqtt is there and set-up)
|
||||
if always_mqtt or (project.fedmsg_hook and project.fedmsg_hook.active):
|
||||
try:
|
||||
print(" - to mqtt")
|
||||
pagure.lib.notify.mqtt_publish(topic, msg)
|
||||
except Exception:
|
||||
_log.exception("Error sending stomp notifications on commit push")
|
||||
|
||||
|
||||
def send_webhook_notifications(project, topic, msg):
|
||||
""" If the user asked for webhook notifications on commit, this will
|
||||
do it.
|
||||
"""
|
||||
if project.settings.get("Web-hooks"):
|
||||
try:
|
||||
print(" - to web-hooks")
|
||||
pagure.lib.tasks_services.webhook_notification.delay(
|
||||
topic=topic,
|
||||
msg=msg,
|
||||
namespace=project.namespace,
|
||||
name=project.name,
|
||||
user=project.user.username if project.is_fork else None,
|
||||
)
|
||||
except Exception:
|
||||
_log.exception(
|
||||
"Error sending web-hook notifications on commit push"
|
||||
)
|
||||
|
||||
|
||||
def send_notifications(session, project, repodir, user, refname, revs, forced):
|
||||
""" Send out-going notifications about the commits that have just been
|
||||
pushed.
|
||||
"""
|
||||
|
||||
auths = set()
|
||||
for rev in revs:
|
||||
email = pagure.lib.git.get_author_email(rev, repodir)
|
||||
name = pagure.lib.git.get_author(rev, repodir)
|
||||
author = pagure.lib.query.search_user(session, email=email) or name
|
||||
auths.add(author)
|
||||
|
||||
authors = []
|
||||
for author in auths:
|
||||
if not isinstance(author, six.string_types):
|
||||
author = author.to_json(public=True)
|
||||
authors.append(author)
|
||||
|
||||
if revs:
|
||||
revs.reverse()
|
||||
print("* Publishing information for %i commits" % len(revs))
|
||||
|
||||
topic = "git.receive"
|
||||
msg = dict(
|
||||
total_commits=len(revs),
|
||||
start_commit=revs[0],
|
||||
end_commit=revs[-1],
|
||||
branch=refname,
|
||||
forced=forced,
|
||||
authors=list(authors),
|
||||
agent=user,
|
||||
repo=project.to_json(public=True)
|
||||
if not isinstance(project, six.string_types)
|
||||
else project,
|
||||
)
|
||||
|
||||
# Send blink notification to any 3rd party plugins, if there are any
|
||||
pagure.lib.notify.blinker_publish(topic, msg)
|
||||
|
||||
if not project.private:
|
||||
send_fedmsg_notifications(project, topic, msg)
|
||||
send_stomp_notifications(project, topic, msg)
|
||||
send_mqtt_notifications(project, topic, msg)
|
||||
send_webhook_notifications(project, topic, msg)
|
||||
|
||||
if (
|
||||
_config.get("PAGURE_CI_SERVICES")
|
||||
and project.ci_hook
|
||||
and project.ci_hook.active_commit
|
||||
and not project.private
|
||||
):
|
||||
pagure.lib.tasks_services.trigger_ci_build.delay(
|
||||
project_name=project.fullname,
|
||||
cause=revs[-1],
|
||||
branch=refname,
|
||||
ci_type=project.ci_hook.ci_type,
|
||||
)
|
||||
|
||||
|
||||
def inform_pull_request_urls(
|
||||
session, project, commits, refname, default_branch
|
||||
):
|
||||
""" Inform the user about the URLs to open a new pull-request or visit
|
||||
the existing one.
|
||||
"""
|
||||
target_repo = project
|
||||
if project.is_fork:
|
||||
target_repo = project.parent
|
||||
|
||||
pr_uids = []
|
||||
|
||||
if (
|
||||
commits
|
||||
and refname != default_branch
|
||||
and target_repo.settings.get("pull_requests", True)
|
||||
):
|
||||
print()
|
||||
prs = pagure.lib.query.search_pull_requests(
|
||||
session,
|
||||
project_id_from=target_repo.id,
|
||||
status="Open",
|
||||
branch_from=refname,
|
||||
)
|
||||
if project.id != target_repo.id:
|
||||
prs.extend(
|
||||
pagure.lib.query.search_pull_requests(
|
||||
session,
|
||||
project_id_from=project.id,
|
||||
status="Open",
|
||||
branch_from=refname,
|
||||
)
|
||||
)
|
||||
# Link to existing PRs if there are any
|
||||
seen = len(prs) != 0
|
||||
for pr in prs:
|
||||
# Refresh the PR in the db and everywhere else where needed
|
||||
pagure.lib.tasks.update_pull_request.delay(pr.uid)
|
||||
|
||||
# Link tickets with pull-requests if the commit mentions it
|
||||
pagure.lib.tasks.link_pr_to_ticket.delay(pr.uid)
|
||||
|
||||
# Inform the user about the PR
|
||||
print("View pull-request for %s" % refname)
|
||||
print(
|
||||
" %s/%s/pull-request/%s"
|
||||
% (_config["APP_URL"].rstrip("/"), pr.project.url_path, pr.id)
|
||||
)
|
||||
pr_uids.append(pr.uid)
|
||||
|
||||
# If no existing PRs, provide the link to open one
|
||||
if not seen:
|
||||
print("Create a pull-request for %s" % refname)
|
||||
print(
|
||||
" %s/%s/diff/%s..%s"
|
||||
% (
|
||||
_config["APP_URL"].rstrip("/"),
|
||||
project.url_path,
|
||||
default_branch,
|
||||
refname,
|
||||
)
|
||||
)
|
||||
print()
|
||||
|
||||
return pr_uids
|
||||
|
||||
|
||||
class DefaultRunner(BaseRunner):
|
||||
""" Runner for the default hook."""
|
||||
|
||||
@staticmethod
|
||||
def post_receive(session, username, project, repotype, repodir, changes):
|
||||
""" Run the default post-receive hook.
|
||||
|
||||
For args, see BaseRunner.runhook.
|
||||
"""
|
||||
if repotype != "main":
|
||||
if _config.get("HOOK_DEBUG", False):
|
||||
print("Default hook only runs on the main project repository")
|
||||
return
|
||||
|
||||
if changes:
|
||||
# Retrieve the default branch
|
||||
repo_obj = pygit2.Repository(repodir)
|
||||
default_branch = None
|
||||
if not repo_obj.is_empty and not repo_obj.head_is_unborn:
|
||||
default_branch = repo_obj.head.shorthand
|
||||
|
||||
pr_uids = []
|
||||
|
||||
for refname in changes:
|
||||
(oldrev, newrev) = changes[refname]
|
||||
|
||||
forced = False
|
||||
if set(newrev) == set(["0"]):
|
||||
print(
|
||||
"Deleting a reference/branch, so we won't run the "
|
||||
"pagure hook"
|
||||
)
|
||||
return
|
||||
elif set(oldrev) == set(["0"]):
|
||||
oldrev = "^%s" % oldrev
|
||||
elif pagure.lib.git.is_forced_push(oldrev, newrev, repodir):
|
||||
forced = True
|
||||
base = pagure.lib.git.get_base_revision(
|
||||
oldrev, newrev, repodir
|
||||
)
|
||||
if base:
|
||||
oldrev = base[0]
|
||||
|
||||
refname = refname.replace("refs/heads/", "")
|
||||
commits = pagure.lib.git.get_revs_between(
|
||||
oldrev, newrev, repodir, refname
|
||||
)
|
||||
|
||||
log_all = _config.get("LOG_ALL_COMMITS", False)
|
||||
if log_all or refname == default_branch:
|
||||
print(
|
||||
"Sending to redis to log activity and send commit "
|
||||
"notification emails"
|
||||
)
|
||||
else:
|
||||
print("Sending to redis to send commit notification emails")
|
||||
|
||||
# This is logging the commit to the log table in the DB so we can
|
||||
# render commits in the calendar heatmap.
|
||||
# It is also sending emails about commits to people using the
|
||||
# 'watch' feature to be made aware of new commits.
|
||||
pagure.lib.tasks_services.log_commit_send_notifications.delay(
|
||||
name=project.name,
|
||||
commits=commits,
|
||||
abspath=repodir,
|
||||
branch=refname,
|
||||
default_branch=default_branch,
|
||||
namespace=project.namespace,
|
||||
username=project.user.user if project.is_fork else None,
|
||||
)
|
||||
|
||||
# This one is sending fedmsg and web-hook notifications for project
|
||||
# that set them up
|
||||
send_notifications(
|
||||
session, project, repodir, username, refname, commits, forced
|
||||
)
|
||||
|
||||
# Now display to the user if this isn't the default branch links to
|
||||
# open a new pr or review the existing one
|
||||
pr_uids.extend(
|
||||
inform_pull_request_urls(
|
||||
session, project, commits, refname, default_branch
|
||||
)
|
||||
)
|
||||
|
||||
# Refresh of all opened PRs
|
||||
parent = project.parent or project
|
||||
pagure.lib.tasks.refresh_pr_cache(
|
||||
parent.name,
|
||||
parent.namespace,
|
||||
parent.user.user if parent.is_fork else None,
|
||||
but_uids=pr_uids,
|
||||
)
|
||||
|
||||
if not project.is_on_repospanner and _config.get(
|
||||
"GIT_GARBAGE_COLLECT", False
|
||||
):
|
||||
pagure.lib.tasks.git_garbage_collect.delay(
|
||||
project.repopath("main")
|
||||
)
|
||||
|
||||
|
||||
class Default(BaseHook):
|
||||
""" Default hooks. """
|
||||
|
||||
name = "default"
|
||||
description = (
|
||||
"Default hooks that should be enabled for each and every project."
|
||||
)
|
||||
runner = DefaultRunner
|
||||
|
||||
@classmethod
|
||||
def is_enabled_for(cls, project):
|
||||
return True
|
|
@ -380,3 +380,13 @@
|
|||
tags:
|
||||
- pagure
|
||||
- logrotate
|
||||
|
||||
|
||||
- name: hotfix the default hook so it updates pending PR async
|
||||
copy: >
|
||||
src=hotfix-20190227-hooks-default.py
|
||||
dest=/usr/lib/python2.7/site-packages/pagure/hooks/default.py
|
||||
owner=root group=root mode=0644
|
||||
tags:
|
||||
- hotfix
|
||||
- pagure
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue