Blame pagure/lib/tasks.py

Patrick Uiterwijk 0f077b
# -*- coding: utf-8 -*-
Patrick Uiterwijk 0f077b
Patrick Uiterwijk 0f077b
"""
Patrick Uiterwijk 0f077b
 (c) 2017 - Copyright Red Hat Inc
Patrick Uiterwijk 0f077b
Patrick Uiterwijk 0f077b
 Authors:
Patrick Uiterwijk 0f077b
   Patrick Uiterwijk <puiterwijk@redhat.com></puiterwijk@redhat.com>
Patrick Uiterwijk 0f077b
Patrick Uiterwijk 0f077b
"""
Patrick Uiterwijk 0f077b
Aurélien Bompard 831553
from __future__ import unicode_literals
Aurélien Bompard 831553
Pierre-Yves Chibon 716362
import collections
Pierre-Yves Chibon 1828a2
import datetime
Patrick Uiterwijk 9e6fbd
import gc
Pierre-Yves Chibon 36309a
import hashlib
Patrick Uiterwijk 4e3dbd
import os
Patrick Uiterwijk 4e3dbd
import os.path
Patrick Uiterwijk 4e3dbd
import shutil
Patrick Uiterwijk 3f97f6
import subprocess
Patrick Uiterwijk 7b9080
import time
Patrick Uiterwijk 4e3dbd
Pierre-Yves Chibon c2199b
from functools import wraps
Patrick Uiterwijk 0f077b
Pierre-Yves Chibon 1828a2
import arrow
Patrick Uiterwijk 4e3dbd
import pygit2
Patrick Uiterwijk 4e3dbd
import six
Patrick Uiterwijk 4e3dbd
Pierre-Yves Chibon c2199b
from celery import Celery
Pierre-Yves Chibon c2199b
from celery.result import AsyncResult
Pierre-Yves Chibon 24747e
from celery.signals import after_setup_task_logger
Pierre-Yves Chibon 24747e
from celery.utils.log import get_task_logger
Vivek Anand ed7e6e
from sqlalchemy.exc import SQLAlchemyError
Vivek Anand ed7e6e
Patrick Uiterwijk 4e3dbd
import pagure.lib.git
Pierre-Yves Chibon 145998
import pagure.lib.git_auth
Pierre-Yves Chibon 11d019
import pagure.lib.link
Pierre-Yves Chibon 930073
import pagure.lib.query
Patrick Uiterwijk 04c084
import pagure.lib.repo
Pierre-Yves Chibon b130e5
import pagure.utils
Pierre-Yves Chibon b130e5
from pagure.config import config as pagure_config
Pierre-Yves Chibon 11d019
from pagure.utils import get_parent_repo_path
Patrick Uiterwijk 0f077b
Pierre-Yves Chibon b130e5
# logging.config.dictConfig(pagure_config.get('LOGGING') or {'version': 1})
Pierre-Yves Chibon 24747e
_log = get_task_logger(__name__)
Patrick Uiterwijk 96c928
Patrick Uiterwijk 0f077b
Pierre-Yves Chibon 9c2953
if os.environ.get("PAGURE_BROKER_URL"):
Pierre-Yves Chibon 9c2953
    broker_url = os.environ["PAGURE_BROKER_URL"]
Pierre-Yves Chibon 9c2953
elif pagure_config.get("BROKER_URL"):
Pierre-Yves Chibon 9c2953
    broker_url = pagure_config["BROKER_URL"]
Patrick Uiterwijk 55e7e0
else:
Pierre-Yves Chibon 9c2953
    broker_url = "redis://%s" % pagure_config["REDIS_HOST"]
Patrick Uiterwijk 55e7e0
Pierre-Yves Chibon 9c2953
conn = Celery("tasks", broker=broker_url, backend=broker_url)
Pierre-Yves Chibon 9c2953
conn.conf.update(pagure_config["CELERY_CONFIG"])
Patrick Uiterwijk 0f077b
Patrick Uiterwijk 0f077b
Pierre-Yves Chibon 24747e
@after_setup_task_logger.connect
Pierre-Yves Chibon 24747e
def augment_celery_log(**kwargs):
Pierre-Yves Chibon 24747e
    pagure.utils.set_up_logging(force=True)
Pierre-Yves Chibon 24747e
Pierre-Yves Chibon 24747e
Slavek Kabrda efeaa6
def pagure_task(function):
Slavek Kabrda efeaa6
    """ Simple decorator that is responsible for:
Slavek Kabrda efeaa6
    * Adjusting the status of the task when it starts
Slavek Kabrda efeaa6
    * Creating and cleaning up a SQLAlchemy session
Pierre-Yves Chibon bbfb81
    """
Pierre-Yves Chibon bbfb81
Pierre-Yves Chibon bbfb81
    @wraps(function)
Pierre-Yves Chibon bbfb81
    def decorated_function(self, *args, **kwargs):
Pierre-Yves Chibon bbfb81
        """ Decorated function, actually does the work. """
Pierre-Yves Chibon bbfb81
        if self is not None:
Pierre-Yves Chibon f4ddbf
            try:
Pierre-Yves Chibon 9c2953
                self.update_state(state="RUNNING")
Pierre-Yves Chibon f4ddbf
            except TypeError:
Pierre-Yves Chibon f4ddbf
                pass
Pierre-Yves Chibon 930073
        session = pagure.lib.query.create_session(pagure_config["DB_URL"])
Slavek Kabrda efeaa6
        try:
Slavek Kabrda efeaa6
            return function(self, session, *args, **kwargs)
Slavek Kabrda c40ba0
        except:  # noqa: E722
Slavek Kabrda c40ba0
            # if the task has raised for any reason, we need to rollback the
Slavek Kabrda c40ba0
            # session first to not leave open uncomitted transaction hanging
Slavek Kabrda c40ba0
            session.rollback()
Slavek Kabrda c40ba0
            raise
Slavek Kabrda efeaa6
        finally:
Slavek Kabrda efeaa6
            session.remove()
Slavek Kabrda efeaa6
            gc_clean()
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon bbfb81
    return decorated_function
Pierre-Yves Chibon bbfb81
Pierre-Yves Chibon bbfb81
Patrick Uiterwijk 0f077b
def get_result(uuid):
Pierre-Yves Chibon 274e60
    """ Returns the AsyncResult object for a given task.
Pierre-Yves Chibon 274e60
Pierre-Yves Chibon 274e60
    :arg uuid: the unique identifier of the task to retrieve.
Pierre-Yves Chibon 274e60
    :type uuid: str
Pierre-Yves Chibon 274e60
    :return: celery.result.AsyncResult
Pierre-Yves Chibon 274e60
Pierre-Yves Chibon 274e60
    """
Patrick Uiterwijk 0f077b
    return AsyncResult(uuid, conn.backend)
Patrick Uiterwijk 0f077b
Patrick Uiterwijk 0f077b
Patrick Uiterwijk 0f077b
def ret(endpoint, **kwargs):
Pierre-Yves Chibon 9c2953
    toret = {"endpoint": endpoint}
Patrick Uiterwijk 0f077b
    toret.update(kwargs)
Patrick Uiterwijk 0f077b
    return toret
Patrick Uiterwijk 0f077b
Patrick Uiterwijk 0f077b
Patrick Uiterwijk 9e6fbd
def gc_clean():
Pierre-Yves Chibon 274e60
    """ Force a run of the garbage collector. """
Patrick Uiterwijk 9e6fbd
    # https://pagure.io/pagure/issue/2302
Patrick Uiterwijk 9e6fbd
    gc.collect()
Patrick Uiterwijk 9e6fbd
Patrick Uiterwijk 9e6fbd
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("GITOLITE_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Pierre-Yves Chibon 5f2c51
def generate_gitolite_acls(
Pierre-Yves Chibon 9c2953
    self, session, namespace=None, name=None, user=None, group=None
Pierre-Yves Chibon 9c2953
):
Pierre-Yves Chibon 274e60
    """ Generate the gitolite configuration file either entirely or for a
Pierre-Yves Chibon 274e60
    specific project.
Pierre-Yves Chibon 274e60
Slavek Kabrda efeaa6
    :arg session: SQLAlchemy session object
Slavek Kabrda efeaa6
    :type session: sqlalchemy.orm.session.Session
Pierre-Yves Chibon 274e60
    :kwarg namespace: the namespace of the project
Pierre-Yves Chibon ccb160
    :type namespace: None or str
Pierre-Yves Chibon 274e60
    :kwarg name: the name of the project
Pierre-Yves Chibon ccb160
    :type name: None or str
Pierre-Yves Chibon 274e60
    :kwarg user: the user of the project, only set if the project is a fork
Pierre-Yves Chibon ccb160
    :type user: None or str
Pierre-Yves Chibon ccb160
    :kwarg group: the group to refresh the members of
Pierre-Yves Chibon ccb160
    :type group: None or str
Pierre-Yves Chibon 274e60
Pierre-Yves Chibon 274e60
    """
Pierre-Yves Chibon 274e60
    project = None
Pierre-Yves Chibon 274e60
    if name and name != -1:
Pierre-Yves Chibon 930073
        project = pagure.lib.query._get_project(
Pierre-Yves Chibon 9c2953
            session, namespace=namespace, name=name, user=user
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon edbdc9
Pierre-Yves Chibon 274e60
    elif name == -1:
Pierre-Yves Chibon 274e60
        project = name
Patrick Uiterwijk ad0b72
    helper = pagure.lib.git_auth.get_git_auth_helper()
Pierre-Yves Chibon 9c2953
    _log.debug("Got helper: %s", helper)
Pierre-Yves Chibon ccb160
Pierre-Yves Chibon d012ee
    group_obj = None
Pierre-Yves Chibon d012ee
    if group:
Pierre-Yves Chibon 930073
        group_obj = pagure.lib.query.search_groups(session, group_name=group)
Pierre-Yves Chibon ccb160
    _log.debug(
Pierre-Yves Chibon 9c2953
        "Calling helper: %s with arg: project=%s, group=%s",
Pierre-Yves Chibon 9c2953
        helper,
Pierre-Yves Chibon 9c2953
        project,
Pierre-Yves Chibon 9c2953
        group_obj,
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon ccb160
    helper.generate_acls(project=project, group=group_obj)
Pierre-Yves Chibon 5b06f7
Pierre-Yves Chibon 930073
    pagure.lib.query.update_read_only_mode(session, project, read_only=False)
Vivek Anand ed7e6e
    try:
Vivek Anand ed7e6e
        session.commit()
Pierre-Yves Chibon 9c2953
        _log.debug("Project %s is no longer in Read Only Mode", project)
Vivek Anand ed7e6e
    except SQLAlchemyError:
Vivek Anand ed7e6e
        session.rollback()
Pierre-Yves Chibon 9c2953
        _log.exception("Failed to unmark read_only for: %s project", project)
Patrick Uiterwijk 0f077b
Patrick Uiterwijk 0f077b
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("GITOLITE_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Slavek Kabrda 5ab53d
def gitolite_post_compile_only(self, session):
Slavek Kabrda 5ab53d
    """ Do gitolite post-processing only. Most importantly, this processes SSH
Slavek Kabrda 5ab53d
    keys used by gitolite. This is an optimization task that's supposed to be
Slavek Kabrda 5ab53d
    used if you only need to run `gitolite trigger POST_COMPILE` without
Slavek Kabrda 5ab53d
    touching any other gitolite configuration
Slavek Kabrda 5ab53d
    """
Patrick Uiterwijk ad0b72
    helper = pagure.lib.git_auth.get_git_auth_helper()
Pierre-Yves Chibon 9c2953
    _log.debug("Got helper: %s", helper)
Pierre-Yves Chibon 9c2953
    if hasattr(helper, "post_compile_only"):
Slavek Kabrda 5ab53d
        helper.post_compile_only()
Slavek Kabrda 5ab53d
    else:
Slavek Kabrda 5ab53d
        helper.generate_acls(project=None)
Slavek Kabrda 5ab53d
Slavek Kabrda 5ab53d
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("GITOLITE_CELERY_QUEUE", None), bind=True)
Slavek Kabrda 5ab53d
@pagure_task
Pierre-Yves Chibon 5f2c51
def delete_project(
Pierre-Yves Chibon 9c2953
    self, session, namespace=None, name=None, user=None, action_user=None
Pierre-Yves Chibon 9c2953
):
Pierre-Yves Chibon 5b06f7
    """ Delete a project in pagure.
Pierre-Yves Chibon 5b06f7
Pierre-Yves Chibon 5b06f7
    This is achieved in three steps:
Pierre-Yves Chibon 5b06f7
    - Remove the project from gitolite.conf
Pierre-Yves Chibon 5b06f7
    - Remove the git repositories on disk
Pierre-Yves Chibon 5b06f7
    - Remove the project from the DB
Pierre-Yves Chibon 5b06f7
Slavek Kabrda efeaa6
    :arg session: SQLAlchemy session object
Slavek Kabrda efeaa6
    :type session: sqlalchemy.orm.session.Session
Pierre-Yves Chibon 5b06f7
    :kwarg namespace: the namespace of the project
Pierre-Yves Chibon 5b06f7
    :type namespace: None or str
Pierre-Yves Chibon 5b06f7
    :kwarg name: the name of the project
Pierre-Yves Chibon 5b06f7
    :type name: None or str
Pierre-Yves Chibon 5b06f7
    :kwarg user: the user of the project, only set if the project is a fork
Pierre-Yves Chibon 5b06f7
    :type user: None or str
Shaily b11790
    :kwarg action_user: the user deleting the project
Shaily b11790
    :type action_user: None or str
Pierre-Yves Chibon 5b06f7
Pierre-Yves Chibon 5b06f7
    """
Pierre-Yves Chibon 930073
    project = pagure.lib.query._get_project(
Pierre-Yves Chibon 9c2953
        session, namespace=namespace, name=name, user=user
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 5b06f7
Pierre-Yves Chibon 5b06f7
    if not project:
Pierre-Yves Chibon 5b06f7
        raise RuntimeError(
Pierre-Yves Chibon 9c2953
            "Project: %s/%s from user: %s not found in the DB"
Pierre-Yves Chibon 9c2953
            % (namespace, name, user)
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 5b06f7
Pierre-Yves Chibon 5b06f7
    # Remove the project from gitolite.conf
Patrick Uiterwijk ad0b72
    helper = pagure.lib.git_auth.get_git_auth_helper()
Pierre-Yves Chibon 9c2953
    _log.debug("Got helper: %s", helper)
Pierre-Yves Chibon 5b06f7
Pierre-Yves Chibon 5b06f7
    _log.debug(
Pierre-Yves Chibon 9c2953
        "Calling helper: %s with arg: project=%s", helper, project.fullname
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 5b06f7
    helper.remove_acls(session=session, project=project)
Pierre-Yves Chibon 5b06f7
Pierre-Yves Chibon 5b06f7
    # Remove the git repositories on disk
Patrick Uiterwijk 3f97f6
    pagure.lib.git.delete_project_repos(project)
Pierre-Yves Chibon 5b06f7
Pierre-Yves Chibon 5b06f7
    # Remove the project from the DB
Pierre-Yves Chibon 5b06f7
    username = project.user.user
Pierre-Yves Chibon 5b06f7
    try:
Pierre-Yves Chibon 818658
        project_json = project.to_json(public=True)
Pierre-Yves Chibon 5b06f7
        session.delete(project)
Pierre-Yves Chibon 5b06f7
        session.commit()
Shaily b11790
        pagure.lib.notify.log(
Shaily b11790
            project,
Pierre-Yves Chibon 9c2953
            topic="project.deleted",
Pierre-Yves Chibon 9c2953
            msg=dict(project=project_json, agent=action_user),
Shaily b11790
        )
Pierre-Yves Chibon 5b06f7
    except SQLAlchemyError:
Pierre-Yves Chibon 5b06f7
        session.rollback()
Pierre-Yves Chibon 5b06f7
        _log.exception(
Pierre-Yves Chibon 9c2953
            "Failed to delete project: %s from the DB", project.fullname
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 5b06f7
Pierre-Yves Chibon 9c2953
    return ret("ui_ns.view_user", username=username)
Pierre-Yves Chibon 5b06f7
Pierre-Yves Chibon 5b06f7
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("FAST_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Pierre-Yves Chibon 9c2953
def create_project(
Pierre-Yves Chibon 9c2953
    self, session, username, namespace, name, add_readme, ignore_existing_repo
Pierre-Yves Chibon 9c2953
):
Pierre-Yves Chibon 274e60
    """ Create a project.
Pierre-Yves Chibon 274e60
Slavek Kabrda efeaa6
    :arg session: SQLAlchemy session object
Slavek Kabrda efeaa6
    :type session: sqlalchemy.orm.session.Session
Pierre-Yves Chibon 274e60
    :kwarg username: the user creating the project
Pierre-Yves Chibon 274e60
    :type user: str
Pierre-Yves Chibon 274e60
    :kwarg namespace: the namespace of the project
Pierre-Yves Chibon 274e60
    :type namespace: str
Pierre-Yves Chibon 274e60
    :kwarg name: the name of the project
Pierre-Yves Chibon 274e60
    :type name: str
Pierre-Yves Chibon 274e60
    :kwarg add_readme: a boolean specifying if the project should be
Pierre-Yves Chibon 274e60
        created with a README file or not
Pierre-Yves Chibon 274e60
    :type add_readme: bool
Pierre-Yves Chibon 274e60
    :kwarg ignore_existing_repo: a boolean specifying whether the creation
Pierre-Yves Chibon 274e60
        of the project should fail if the repo exists on disk or not
Pierre-Yves Chibon 274e60
    :type ignore_existing_repo: bool
Pierre-Yves Chibon 274e60
Pierre-Yves Chibon 274e60
    """
Pierre-Yves Chibon 930073
    project = pagure.lib.query._get_project(
Pierre-Yves Chibon 930073
        session, namespace=namespace, name=name
Pierre-Yves Chibon 930073
    )
Pierre-Yves Chibon edbdc9
Pierre-Yves Chibon 930073
    userobj = pagure.lib.query.search_user(session, username=username)
Patrick Uiterwijk 7b9080
Pierre-Yves Chibon 6c716f
    # Add the readme file if it was asked
Pierre-Yves Chibon 6c716f
    templ = None
Pierre-Yves Chibon 6c716f
    if project.is_fork:
Pierre-Yves Chibon 6c716f
        templ = pagure_config.get("FORK_TEMPLATE_PATH")
Pierre-Yves Chibon 6c716f
    else:
Pierre-Yves Chibon 6c716f
        templ = pagure_config.get("PROJECT_TEMPLATE_PATH")
Pierre-Yves Chibon 6c716f
    if templ:
Pierre-Yves Chibon 6c716f
        if not os.path.exists(templ):
Pierre-Yves Chibon 6c716f
            _log.warning(
Pierre-Yves Chibon 114311
                "Invalid git template configured: %s, not found on disk", templ
Pierre-Yves Chibon 6c716f
            )
Pierre-Yves Chibon 6c716f
            templ = None
Patrick Uiterwijk 7b9080
        else:
Pierre-Yves Chibon 6c716f
            _log.debug("  Using template at: %s", templ)
Pierre-Yves Chibon 75a89d
Pierre-Yves Chibon 7834b6
    # There is a risk for a race-condition here between when the repo is
Pierre-Yves Chibon 7834b6
    # created and when the README gets added. However, this risk is small
Pierre-Yves Chibon 7834b6
    # enough that we will keep this as is for now (esp since it fixes the
Pierre-Yves Chibon 7834b6
    # situation where deleting the project raised an error if it was in the
Pierre-Yves Chibon 7834b6
    # middle of the lock)
Pierre-Yves Chibon 6c716f
    try:
Pierre-Yves Chibon 6c716f
        with project.lock("WORKER"):
Patrick Uiterwijk 6876a8
            pagure.lib.git.create_project_repos(
Patrick Uiterwijk 6876a8
                project,
Patrick Uiterwijk 6876a8
                project.repospanner_region,
Patrick Uiterwijk 6876a8
                templ,
Patrick Uiterwijk 6876a8
                ignore_existing_repo,
Patrick Uiterwijk 6876a8
            )
Pierre-Yves Chibon 6c716f
    except pagure.exceptions.RepoExistsException:
Pierre-Yves Chibon 6c716f
        session.delete(project)
Pierre-Yves Chibon 6c716f
        session.commit()
Pierre-Yves Chibon 6c716f
        raise
Pierre-Yves Chibon 42df12
Pierre-Yves Chibon 6c716f
    if add_readme:
Pierre-Yves Chibon 6c716f
        with project.lock("WORKER"):
Patrick Uiterwijk 3f97f6
            with pagure.lib.git.TemporaryClone(
Patrick Uiterwijk 3f97f6
                project, "main", "add_readme"
Patrick Uiterwijk 3f97f6
            ) as tempclone:
Patrick Uiterwijk 3f97f6
                temp_gitrepo = tempclone.repo
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
                # Add README file
Patrick Uiterwijk 3f97f6
                author = userobj.fullname or userobj.user
Patrick Uiterwijk 3f97f6
                author_email = userobj.default_email
Patrick Uiterwijk 3f97f6
                if six.PY2:
Patrick Uiterwijk 3f97f6
                    author = author.encode("utf-8")
Patrick Uiterwijk 3f97f6
                    author_email = author_email.encode("utf-8")
Patrick Uiterwijk 3f97f6
                author = pygit2.Signature(author, author_email)
Patrick Uiterwijk 3f97f6
                content = "# %s\n\n%s" % (name, project.description)
Patrick Uiterwijk 3f97f6
                readme_file = os.path.join(temp_gitrepo.workdir, "README.md")
Patrick Uiterwijk 3f97f6
                with open(readme_file, "wb") as stream:
Patrick Uiterwijk 3f97f6
                    stream.write(content.encode("utf-8"))
Patrick Uiterwijk 3f97f6
                temp_gitrepo.index.add_all()
Patrick Uiterwijk 3f97f6
                temp_gitrepo.index.write()
Patrick Uiterwijk 3f97f6
                tree = temp_gitrepo.index.write_tree()
Patrick Uiterwijk 3f97f6
                temp_gitrepo.create_commit(
Patrick Uiterwijk 3f97f6
                    "HEAD", author, author, "Added the README", tree, []
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 42df12
Patrick Uiterwijk 3f97f6
                master_ref = temp_gitrepo.lookup_reference("HEAD").resolve()
Patrick Uiterwijk 03a519
                tempclone.push("pagure", master_ref.name, internal="yes")
Patrick Uiterwijk 7b9080
Pierre-Yves Chibon 6c716f
            # Install the default hook
Pierre-Yves Chibon 6c716f
            plugin = pagure.lib.plugins.get_plugin("default")
Pierre-Yves Chibon 6c716f
            dbobj = plugin.db_object()
Pierre-Yves Chibon 6c716f
            dbobj.active = True
Pierre-Yves Chibon 6c716f
            dbobj.project_id = project.id
Pierre-Yves Chibon 6c716f
            session.add(dbobj)
Pierre-Yves Chibon 6c716f
            session.flush()
Pierre-Yves Chibon 6c716f
            plugin.set_up(project)
Pierre-Yves Chibon 6c716f
            plugin.install(project, dbobj)
Pierre-Yves Chibon 6c716f
            session.commit()
Patrick Uiterwijk 4e3dbd
Pierre-Yves Chibon 56e29f
    task = generate_gitolite_acls.delay(
Pierre-Yves Chibon 274e60
        namespace=project.namespace,
Pierre-Yves Chibon 274e60
        name=project.name,
Pierre-Yves Chibon 9c2953
        user=project.user.user if project.is_fork else None,
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
    _log.info("Refreshing gitolite config queued in task: %s", task.id)
Pierre-Yves Chibon 274e60
Pierre-Yves Chibon 9c2953
    return ret("ui_ns.view_repo", repo=name, namespace=namespace)
Patrick Uiterwijk 8e1ee6
Patrick Uiterwijk 8e1ee6
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("SLOW_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Pierre-Yves Chibon 9c2953
def update_git(
Pierre-Yves Chibon 9c2953
    self, session, name, namespace, user, ticketuid=None, requestuid=None
Pierre-Yves Chibon 9c2953
):
Pierre-Yves Chibon 314da3
    """ Update the JSON representation of either a ticket or a pull-request
Pierre-Yves Chibon 314da3
    depending on the argument specified.
Pierre-Yves Chibon 314da3
    """
Pierre-Yves Chibon 930073
    project = pagure.lib.query._get_project(
Pierre-Yves Chibon 9c2953
        session, namespace=namespace, name=name, user=user
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon edbdc9
Pierre-Yves Chibon 9c2953
    project_lock = "WORKER"
Pierre-Yves Chibon 09776e
    if ticketuid is not None:
Pierre-Yves Chibon 9c2953
        project_lock = "WORKER_TICKET"
Pierre-Yves Chibon 09776e
    elif requestuid is not None:
Pierre-Yves Chibon 9c2953
        project_lock = "WORKER_REQUEST"
Pierre-Yves Chibon 09776e
Pierre-Yves Chibon 09776e
    with project.lock(project_lock):
Patrick Uiterwijk 7b9080
        if ticketuid is not None:
Pierre-Yves Chibon 930073
            obj = pagure.lib.query.get_issue_by_uid(session, ticketuid)
Patrick Uiterwijk 7b9080
        elif requestuid is not None:
Pierre-Yves Chibon 930073
            obj = pagure.lib.query.get_request_by_uid(session, requestuid)
Patrick Uiterwijk 7b9080
        else:
Pierre-Yves Chibon 9c2953
            raise NotImplementedError("No ticket ID or request ID provided")
Patrick Uiterwijk 7b9080
Patrick Uiterwijk 7b9080
        if obj is None:
Pierre-Yves Chibon 9c2953
            raise Exception("Unable to find object")
Patrick Uiterwijk 7b9080
Patrick Uiterwijk 3f97f6
        result = pagure.lib.git._update_git(obj, project)
Patrick Uiterwijk 8e1ee6
Patrick Uiterwijk 120396
    return result
Patrick Uiterwijk 189fa8
Patrick Uiterwijk 189fa8
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("SLOW_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Patrick Uiterwijk 3f97f6
def clean_git(self, session, name, namespace, user, obj_repotype, obj_uid):
Pierre-Yves Chibon 314da3
    """ Remove the JSON representation of a ticket on the git repository
Pierre-Yves Chibon 314da3
    for tickets.
Pierre-Yves Chibon 314da3
    """
Pierre-Yves Chibon 930073
    project = pagure.lib.query._get_project(
Pierre-Yves Chibon 9c2953
        session, namespace=namespace, name=name, user=user
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon edbdc9
Pierre-Yves Chibon 9c2953
    with project.lock("WORKER_TICKET"):
Patrick Uiterwijk 3f97f6
        result = pagure.lib.git._clean_git(project, obj_repotype, obj_uid)
Patrick Uiterwijk 189fa8
Patrick Uiterwijk 189fa8
    return result
Patrick Uiterwijk 8cb224
Patrick Uiterwijk 8cb224
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("MEDIUM_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Pierre-Yves Chibon 9c2953
def update_file_in_git(
Pierre-Yves Chibon 9c2953
    self,
Pierre-Yves Chibon 9c2953
    session,
Pierre-Yves Chibon 9c2953
    name,
Pierre-Yves Chibon 9c2953
    namespace,
Pierre-Yves Chibon 9c2953
    user,
Pierre-Yves Chibon 9c2953
    branch,
Pierre-Yves Chibon 9c2953
    branchto,
Pierre-Yves Chibon 9c2953
    filename,
Pierre-Yves Chibon 9c2953
    content,
Pierre-Yves Chibon 9c2953
    message,
Pierre-Yves Chibon 9c2953
    username,
Pierre-Yves Chibon 9c2953
    email,
Pierre-Yves Chibon 9c2953
):
Pierre-Yves Chibon 314da3
    """ Update a file in the specified git repo.
Pierre-Yves Chibon 314da3
    """
Pierre-Yves Chibon 930073
    userobj = pagure.lib.query.search_user(session, username=username)
Pierre-Yves Chibon 930073
    project = pagure.lib.query._get_project(
Pierre-Yves Chibon 9c2953
        session, namespace=namespace, name=name, user=user
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk 8cb224
Pierre-Yves Chibon 9c2953
    with project.lock("WORKER"):
Pierre-Yves Chibon 715218
        pagure.lib.git._update_file_in_git(
Pierre-Yves Chibon 9c2953
            project,
Pierre-Yves Chibon 9c2953
            branch,
Pierre-Yves Chibon 9c2953
            branchto,
Pierre-Yves Chibon 9c2953
            filename,
Pierre-Yves Chibon 9c2953
            content,
Pierre-Yves Chibon 9c2953
            message,
Pierre-Yves Chibon 9c2953
            userobj,
Pierre-Yves Chibon 9c2953
            email,
Pierre-Yves Chibon 9c2953
        )
Patrick Uiterwijk 8cb224
Pierre-Yves Chibon 9c2953
    return ret(
Pierre-Yves Chibon 9c2953
        "ui_ns.view_commits",
Pierre-Yves Chibon 9c2953
        repo=project.name,
Pierre-Yves Chibon 9c2953
        username=user,
Pierre-Yves Chibon 9c2953
        namespace=namespace,
Pierre-Yves Chibon 9c2953
        branchname=branchto,
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk 8cb224
Patrick Uiterwijk 8cb224
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("MEDIUM_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Slavek Kabrda efeaa6
def delete_branch(self, session, name, namespace, user, branchname):
Pierre-Yves Chibon 314da3
    """ Delete a branch from a git repo.
Pierre-Yves Chibon 314da3
    """
Pierre-Yves Chibon 930073
    project = pagure.lib.query._get_project(
Pierre-Yves Chibon 9c2953
        session, namespace=namespace, name=name, user=user
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon edbdc9
Pierre-Yves Chibon 9c2953
    with project.lock("WORKER"):
Pierre-Yves Chibon 9c2953
        repo_obj = pygit2.Repository(pagure.utils.get_repo_path(project))
Patrick Uiterwijk 8cb224
Patrick Uiterwijk 7b9080
        try:
Patrick Uiterwijk 7b9080
            branch = repo_obj.lookup_branch(branchname)
Patrick Uiterwijk 7b9080
            branch.delete()
Patrick Uiterwijk 7b9080
        except pygit2.GitError as err:
Patrick Uiterwijk 7b9080
            _log.exception(err)
Patrick Uiterwijk 8cb224
Pierre-Yves Chibon b130e5
    return ret(
Ryan Lerch 2867e2
        "ui_ns.view_branches", repo=name, namespace=namespace, username=user
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk ac056b
Patrick Uiterwijk ac056b
Pierre-Yves Chibon 974201
@conn.task(queue=pagure_config.get("MEDIUM_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Pierre-Yves Chibon 9c2953
def fork(
Pierre-Yves Chibon 9c2953
    self,
Pierre-Yves Chibon 9c2953
    session,
Pierre-Yves Chibon 9c2953
    name,
Pierre-Yves Chibon 9c2953
    namespace,
Pierre-Yves Chibon 9c2953
    user_owner,
Pierre-Yves Chibon 9c2953
    user_forker,
Pierre-Yves Chibon 9c2953
    editbranch,
Pierre-Yves Chibon 9c2953
    editfile,
Pierre-Yves Chibon 9c2953
):
Pierre-Yves Chibon 274e60
    """ Forks the specified project for the specified user.
Pierre-Yves Chibon 274e60
Pierre-Yves Chibon 274e60
    :arg namespace: the namespace of the project
Pierre-Yves Chibon 274e60
    :type namespace: str
Pierre-Yves Chibon 274e60
    :arg name: the name of the project
Pierre-Yves Chibon 274e60
    :type name: str
Pierre-Yves Chibon 274e60
    :arg user_owner: the user of which the project is forked, only set
Pierre-Yves Chibon 274e60
        if the project is already a fork
Pierre-Yves Chibon 274e60
    :type user_owner: str
Pierre-Yves Chibon 274e60
    :arg user_forker: the user forking the project
Pierre-Yves Chibon 274e60
    :type user_forker: str
Pierre-Yves Chibon 274e60
    :kwarg editbranch: the name of the branch in which the user asked to
Pierre-Yves Chibon 274e60
        edit a file
Pierre-Yves Chibon 274e60
    :type editbranch: str
Pierre-Yves Chibon 274e60
    :kwarg editfile: the file the user asked to edit
Pierre-Yves Chibon 274e60
    :type editfile: str
Pierre-Yves Chibon 274e60
Pierre-Yves Chibon 274e60
    """
Pierre-Yves Chibon 930073
    repo_from = pagure.lib.query._get_project(
Pierre-Yves Chibon 9c2953
        session, namespace=namespace, name=name, user=user_owner
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon edbdc9
Pierre-Yves Chibon 930073
    repo_to = pagure.lib.query._get_project(
Pierre-Yves Chibon 9c2953
        session, namespace=namespace, name=name, user=user_forker
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk 7b9080
Pierre-Yves Chibon 9c2953
    with repo_to.lock("WORKER"):
Patrick Uiterwijk 3f97f6
        pagure.lib.git.create_project_repos(
Patrick Uiterwijk 3f97f6
            repo_to, repo_to.repospanner_region, None, False
Patrick Uiterwijk 3f97f6
        )
Patrick Uiterwijk 7b9080
Patrick Uiterwijk 3f97f6
        with pagure.lib.git.TemporaryClone(
Patrick Uiterwijk 3f97f6
            repo_to, "main", "fork"
Patrick Uiterwijk 3f97f6
        ) as tempclone:
Patrick Uiterwijk 3f97f6
            fork_repo = tempclone.repo
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
            fork_repo.remotes.create("forkedfrom", repo_from.repopath("main"))
Patrick Uiterwijk 3f97f6
            fork_repo.remotes["forkedfrom"].fetch()
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
            for branchname in fork_repo.branches.remote:
Patrick Uiterwijk 3f97f6
                if not branchname.startswith("forkedfrom/"):
Patrick Uiterwijk 3f97f6
                    continue
Patrick Uiterwijk 3f97f6
                localname = branchname.replace("forkedfrom/", "")
Patrick Uiterwijk 3f97f6
                if localname == "HEAD":
Patrick Uiterwijk 3f97f6
                    # HEAD will be created automatically as a symref
Patrick Uiterwijk 3f97f6
                    continue
Patrick Uiterwijk 3f97f6
                tempclone.push(
Patrick Uiterwijk 03a519
                    "pagure",
Patrick Uiterwijk 03a519
                    "remotes/%s" % branchname,
Patrick Uiterwijk 03a519
                    "refs/heads/%s" % localname,
Patrick Uiterwijk 03a519
                    internal="yes",
Pierre-Yves Chibon 42df12
                )
Patrick Uiterwijk 7b9080
Patrick Uiterwijk 3f97f6
        if not repo_to.is_on_repospanner and not repo_to.private:
Patrick Uiterwijk 3f97f6
            # Create the git-daemon-export-ok file on the clone
Patrick Uiterwijk 3f97f6
            http_clone_file = os.path.join(
Patrick Uiterwijk 3f97f6
                repo_to.repopath("main"), "git-daemon-export-ok"
Patrick Uiterwijk 7b9080
            )
Patrick Uiterwijk 3f97f6
            if not os.path.exists(http_clone_file):
Patrick Uiterwijk 3f97f6
                with open(http_clone_file, "w"):
Patrick Uiterwijk 3f97f6
                    pass
Patrick Uiterwijk 7b9080
Patrick Uiterwijk 7b9080
        pagure.lib.notify.log(
Patrick Uiterwijk 7b9080
            repo_to,
Pierre-Yves Chibon 9c2953
            topic="project.forked",
Pierre-Yves Chibon 9c2953
            msg=dict(project=repo_to.to_json(public=True), agent=user_forker),
Patrick Uiterwijk ac056b
        )
Patrick Uiterwijk ac056b
Pierre-Yves Chibon 9c2953
    _log.info("Project created, refreshing auth async")
Pierre-Yves Chibon 56e29f
    task = generate_gitolite_acls.delay(
Pierre-Yves Chibon 274e60
        namespace=repo_to.namespace,
Pierre-Yves Chibon 274e60
        name=repo_to.name,
Pierre-Yves Chibon 9c2953
        user=repo_to.user.user if repo_to.is_fork else None,
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
    _log.info("Refreshing gitolite config queued in task: %s", task.id)
Patrick Uiterwijk 2a3bd8
Patrick Uiterwijk 2a3bd8
    if editfile is None:
Pierre-Yves Chibon 9c2953
        return ret(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_repo",
Pierre-Yves Chibon 9c2953
            repo=name,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
            username=user_forker,
Pierre-Yves Chibon 9c2953
        )
Patrick Uiterwijk 2a3bd8
    else:
Pierre-Yves Chibon 9c2953
        return ret(
Pierre-Yves Chibon 9c2953
            "ui_ns.edit_file",
Pierre-Yves Chibon 9c2953
            repo=name,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
            username=user_forker,
Pierre-Yves Chibon 9c2953
            branchname=editbranch,
Pierre-Yves Chibon 9c2953
            filename=editfile,
Pierre-Yves Chibon 9c2953
        )
Patrick Uiterwijk c0c627
Patrick Uiterwijk c0c627
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("FAST_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Slavek Kabrda efeaa6
def pull_remote_repo(self, session, remote_git, branch_from):
Pierre-Yves Chibon 314da3
    """ Clone a remote git repository locally for remote PRs.
Pierre-Yves Chibon 314da3
    """
Pierre-Yves Chibon f2db4b
Pierre-Yves Chibon b9d537
    clonepath = pagure.utils.get_remote_repo_path(
Pierre-Yves Chibon 9c2953
        remote_git, branch_from, ignore_non_exist=True
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon b9d537
Patrick Uiterwijk 9e6fbd
    repo = pygit2.clone_repository(
Pierre-Yves Chibon 9c2953
        remote_git, clonepath, checkout_branch=branch_from
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk c0c627
Patrick Uiterwijk 9e6fbd
    del repo
Patrick Uiterwijk 226add
    return clonepath
Patrick Uiterwijk c6f63a
Patrick Uiterwijk c6f63a
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("MEDIUM_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Slavek Kabrda efeaa6
def refresh_remote_pr(self, session, name, namespace, user, requestid):
Pierre-Yves Chibon 314da3
    """ Refresh the local clone of a git repository used in a remote
Pierre-Yves Chibon 314da3
    pull-request.
Pierre-Yves Chibon 314da3
    """
Pierre-Yves Chibon 930073
    project = pagure.lib.query._get_project(
Pierre-Yves Chibon 9c2953
        session, namespace=namespace, name=name, user=user
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk 04c084
Pierre-Yves Chibon 930073
    request = pagure.lib.query.search_pull_requests(
Pierre-Yves Chibon 9c2953
        session, project_id=project.id, requestid=requestid
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk 04c084
    _log.debug(
Pierre-Yves Chibon 9c2953
        "refreshing remote pull-request: %s/#%s",
Pierre-Yves Chibon 9c2953
        request.project.fullname,
Pierre-Yves Chibon 9c2953
        request.id,
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk 04c084
Pierre-Yves Chibon b8cacb
    clonepath = pagure.utils.get_remote_repo_path(
Pierre-Yves Chibon 9c2953
        request.remote_git, request.branch_from
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk 04c084
Patrick Uiterwijk 04c084
    repo = pagure.lib.repo.PagureRepo(clonepath)
Patrick Uiterwijk 04c084
    repo.pull(branch=request.branch_from, force=True)
Patrick Uiterwijk 04c084
Patrick Uiterwijk 04c084
    refresh_pr_cache.delay(name, namespace, user)
Patrick Uiterwijk 04c084
    del repo
Pierre-Yves Chibon b130e5
    return ret(
Pierre-Yves Chibon 9c2953
        "ui_ns.request_pull",
Pierre-Yves Chibon 9c2953
        username=user,
Pierre-Yves Chibon 9c2953
        namespace=namespace,
Pierre-Yves Chibon 9c2953
        repo=name,
Pierre-Yves Chibon 9c2953
        requestid=requestid,
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk 04c084
Patrick Uiterwijk 04c084
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("FAST_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Patrick Uiterwijk 3f97f6
def move_to_repospanner(self, session, name, namespace, user, region):
Patrick Uiterwijk 3f97f6
    """ Move a repository to a repoSpanner region.
Patrick Uiterwijk 3f97f6
    """
Pierre-Yves Chibon 930073
    project = pagure.lib.query._get_project(
Patrick Uiterwijk 3f97f6
        session, namespace=namespace, name=name, user=user
Patrick Uiterwijk 3f97f6
    )
Patrick Uiterwijk 3f97f6
    regioninfo = pagure_config.get("REPOSPANNER_REGIONS", {}).get(region)
Patrick Uiterwijk 3f97f6
    if not regioninfo:
Patrick Uiterwijk 3f97f6
        raise Exception("Missing region config")
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
    with project.lock("WORKER"):
Patrick Uiterwijk 3f97f6
        # Perform some pre-flight checks
Patrick Uiterwijk 3f97f6
        if project.is_on_repospanner:
Patrick Uiterwijk 3f97f6
            raise Exception("Project is already on repoSpanner")
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        #  Make sure that no non-runner hooks are enabled for this project
Pierre-Yves Chibon 930073
        compatible_targets = [pagure.lib.query.HOOK_DNE_TARGET]
Patrick Uiterwijk 3f97f6
        incompatible_hooks = []
Pierre-Yves Chibon 930073
        for repotype in pagure.lib.query.REPOTYPES:
Patrick Uiterwijk 3f97f6
            path = project.repopath(repotype)
Patrick Uiterwijk c08d9c
            if path is None:
Patrick Uiterwijk c08d9c
                continue
Patrick Uiterwijk 3f97f6
            hookpath = os.path.join(path, "hooks")
Patrick Uiterwijk 3f97f6
            for hook in os.listdir(hookpath):
Patrick Uiterwijk 3f97f6
                if not hook.startswith(
Patrick Uiterwijk 3f97f6
                    ("pre-receive.", "update.", "post-receive.")
Patrick Uiterwijk 3f97f6
                ):
Patrick Uiterwijk 3f97f6
                    continue
Patrick Uiterwijk 05520e
                if hook.endswith(".sample"):
Patrick Uiterwijk 05520e
                    # Ignore the samples that Git inserts
Patrick Uiterwijk 05520e
                    continue
Patrick Uiterwijk 3f97f6
                hookfile = os.path.join(hookpath, hook)
Patrick Uiterwijk 3f97f6
                if os.path.realpath(hookfile) not in compatible_targets:
Patrick Uiterwijk 3f97f6
                    incompatible_hooks.append((repotype, hook))
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        if incompatible_hooks:
Patrick Uiterwijk 3f97f6
            raise Exception(
Patrick Uiterwijk 3f97f6
                "Repository contains repoSpanner-incompatible "
Patrick Uiterwijk 87315e
                "hooks: %s"
Patrick Uiterwijk 87315e
                % ", ".join(["%s" % (hook,) for hook in incompatible_hooks])
Patrick Uiterwijk 3f97f6
            )
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        # Create the repositories
Patrick Uiterwijk 3f97f6
        pagure.lib.git.create_project_repos(project, region, None, False)
Patrick Uiterwijk 3f97f6
Pierre-Yves Chibon 930073
        for repotype in pagure.lib.query.REPOTYPES:
Patrick Uiterwijk 3f97f6
            repopath = project.repopath(repotype)
Patrick Uiterwijk aeb045
            if repopath is None:
Patrick Uiterwijk aeb045
                continue
Patrick Uiterwijk aeb045
            repourl, _ = project.repospanner_repo_info(repotype, region)
Patrick Uiterwijk 3f97f6
            repo_obj = pagure.lib.repo.PagureRepo(repopath)
Patrick Uiterwijk 3f97f6
            repo_obj.create_remote("repospanner_push", repourl)
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
            command = [
Patrick Uiterwijk 3f97f6
                "git",
Patrick Uiterwijk 3f97f6
                "-c",
Patrick Uiterwijk 3f97f6
                "http.sslcainfo=%s" % regioninfo["ca"],
Patrick Uiterwijk 3f97f6
                "-c",
Patrick Uiterwijk 3f97f6
                "http.sslcert=%s" % regioninfo["push_cert"]["cert"],
Patrick Uiterwijk 3f97f6
                "-c",
Patrick Uiterwijk 3f97f6
                "http.sslkey=%s" % regioninfo["push_cert"]["key"],
Patrick Uiterwijk 3f97f6
                "push",
Patrick Uiterwijk 3f97f6
                "--mirror",
Patrick Uiterwijk 3f97f6
                "repospanner_push",
Patrick Uiterwijk 3f97f6
            ]
Patrick Uiterwijk 3f97f6
            _log.debug("Running push command: %s", command)
Patrick Uiterwijk 3f97f6
            out = subprocess.check_output(
Patrick Uiterwijk 3f97f6
                command, cwd=repopath, stderr=subprocess.STDOUT
Patrick Uiterwijk 3f97f6
            )
Patrick Uiterwijk 3f97f6
            _log.debug("Out: %s" % out)
Patrick Uiterwijk 3f97f6
Pierre-Yves Chibon 930073
        for repotype in pagure.lib.query.REPOTYPES:
Patrick Uiterwijk 3f97f6
            repopath = project.repopath(repotype)
Patrick Uiterwijk bad007
            if repopath is None:
Patrick Uiterwijk bad007
                continue
Patrick Uiterwijk 3f97f6
            repo_obj = pagure.lib.repo.PagureRepo(repopath)
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
            # At this moment, this subrepo has been migrated
Patrick Uiterwijk 3f97f6
            # Move the "refs" folder to "refsold", so that we don't actually
Patrick Uiterwijk 3f97f6
            # delete any data, but it's no longer a valid git repo.
Patrick Uiterwijk 3f97f6
            # On next use, a pseudo repository will be created.
Patrick Uiterwijk 3f97f6
            refsdir = os.path.join(repopath, "refs")
Patrick Uiterwijk 3f97f6
            shutil.move(refsdir, refsdir + "old")
Patrick Uiterwijk 3f97f6
            with open(
Patrick Uiterwijk 3f97f6
                os.path.join(repopath, "repospanner_status"), "w"
Patrick Uiterwijk 3f97f6
            ) as info:
Patrick Uiterwijk 3f97f6
                info.write(
Patrick Uiterwijk 3f97f6
                    "This repository has migrated to repoSpanner region %s"
Patrick Uiterwijk 3f97f6
                    % region
Patrick Uiterwijk 3f97f6
                )
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        project.repospanner_region = region
Patrick Uiterwijk 3f97f6
        session.add(project)
Patrick Uiterwijk 3f97f6
        session.commit()
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
    return ret(
Patrick Uiterwijk 3f97f6
        "ui_ns.view_repo", username=user, namespace=namespace, repo=name
Patrick Uiterwijk 3f97f6
    )
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
@conn.task(queue=pagure_config.get("FAST_CELERY_QUEUE", None), bind=True)
Patrick Uiterwijk 3f97f6
@pagure_task
Slavek Kabrda efeaa6
def refresh_pr_cache(self, session, name, namespace, user):
Pierre-Yves Chibon 314da3
    """ Refresh the merge status cached of pull-requests.
Pierre-Yves Chibon 314da3
    """
Pierre-Yves Chibon 930073
    project = pagure.lib.query._get_project(
Pierre-Yves Chibon 9c2953
        session, namespace=namespace, name=name, user=user
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk c6f63a
Pierre-Yves Chibon 930073
    pagure.lib.query.reset_status_pull_request(session, project)
Patrick Uiterwijk c6f63a
Patrick Uiterwijk 3caaa0
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("FAST_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Pierre-Yves Chibon 9c2953
def merge_pull_request(
Pierre-Yves Chibon 9c2953
    self,
Pierre-Yves Chibon 9c2953
    session,
Pierre-Yves Chibon 9c2953
    name,
Pierre-Yves Chibon 9c2953
    namespace,
Pierre-Yves Chibon 9c2953
    user,
Pierre-Yves Chibon 9c2953
    requestid,
Pierre-Yves Chibon 9c2953
    user_merger,
Pierre-Yves Chibon 9c2953
    delete_branch_after=False,
Pierre-Yves Chibon 9c2953
):
Pierre-Yves Chibon 314da3
    """ Merge pull-request.
Pierre-Yves Chibon 314da3
    """
Pierre-Yves Chibon 930073
    project = pagure.lib.query._get_project(
Pierre-Yves Chibon 9c2953
        session, namespace=namespace, name=name, user=user
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon edbdc9
Pierre-Yves Chibon 9c2953
    with project.lock("WORKER"):
Pierre-Yves Chibon 930073
        request = pagure.lib.query.search_pull_requests(
Pierre-Yves Chibon 9c2953
            session, project_id=project.id, requestid=requestid
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 8be363
        _log.debug(
Pierre-Yves Chibon 9c2953
            "Merging pull-request: %s/#%s",
Pierre-Yves Chibon 9c2953
            request.project.fullname,
Pierre-Yves Chibon 9c2953
            request.id,
Pierre-Yves Chibon 9c2953
        )
Patrick Uiterwijk 3f97f6
        pagure.lib.git.merge_pull_request(session, request, user_merger)
Patrick Uiterwijk c6f63a
Lubomír Sedlář 7c6b11
    if delete_branch_after:
Pierre-Yves Chibon 9c2953
        _log.debug(
Pierre-Yves Chibon 9c2953
            "Will delete source branch of pull-request: %s/#%s",
Pierre-Yves Chibon 9c2953
            request.project.fullname,
Pierre-Yves Chibon 9c2953
            request.id,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        owner = (
Pierre-Yves Chibon 9c2953
            request.project_from.user.username
Pierre-Yves Chibon 9c2953
            if request.project_from.parent
Pierre-Yves Chibon 9c2953
            else None
Pierre-Yves Chibon 9c2953
        )
Lubomír Sedlář 7c6b11
        delete_branch.delay(
Lubomír Sedlář 7c6b11
            request.project_from.name,
Lubomír Sedlář 7c6b11
            request.project_from.namespace,
Lubomír Sedlář ed7075
            owner,
Pierre-Yves Chibon 9c2953
            request.branch_from,
Pierre-Yves Chibon 9c2953
        )
Lubomír Sedlář 7c6b11
Patrick Uiterwijk c6f63a
    refresh_pr_cache.delay(name, namespace, user)
Pierre-Yves Chibon b130e5
    return ret(
Pierre-Yves Chibon 9c2953
        "ui_ns.view_repo", repo=name, username=user, namespace=namespace
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk 96c928
Patrick Uiterwijk 96c928
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("FAST_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Pierre-Yves Chibon 9c2953
def add_file_to_git(
Pierre-Yves Chibon 9c2953
    self, session, name, namespace, user, user_attacher, issueuid, filename
Pierre-Yves Chibon 9c2953
):
Pierre-Yves Chibon 314da3
    """ Add a file to the specified git repo.
Pierre-Yves Chibon 314da3
    """
Pierre-Yves Chibon 930073
    project = pagure.lib.query._get_project(
Pierre-Yves Chibon 9c2953
        session, namespace=namespace, name=name, user=user
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon edbdc9
Pierre-Yves Chibon 9c2953
    with project.lock("WORKER"):
Pierre-Yves Chibon 930073
        issue = pagure.lib.query.get_issue_by_uid(session, issueuid)
Pierre-Yves Chibon 930073
        user_attacher = pagure.lib.query.search_user(
Pierre-Yves Chibon 930073
            session, username=user_attacher
Pierre-Yves Chibon 930073
        )
Patrick Uiterwijk 96c928
Pierre-Yves Chibon 9c2953
        from_folder = pagure_config["ATTACHMENTS_FOLDER"]
Pierre-Yves Chibon 8be363
        _log.info(
Patrick Uiterwijk 3f97f6
            "Adding file %s from %s to %s",
Patrick Uiterwijk 3f97f6
            filename,
Patrick Uiterwijk 3f97f6
            from_folder,
Patrick Uiterwijk 3f97f6
            project.fullname,
Pierre-Yves Chibon 9c2953
        )
Patrick Uiterwijk 7b9080
        pagure.lib.git._add_file_to_git(
Patrick Uiterwijk 3f97f6
            project, issue, from_folder, user_attacher, filename
Pierre-Yves Chibon 9c2953
        )
Patrick Uiterwijk 96c928
Patrick Uiterwijk 7b9080
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("MEDIUM_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Slavek Kabrda efeaa6
def project_dowait(self, session, name, namespace, user):
Patrick Uiterwijk 7b9080
    """ This is a task used to test the locking systems.
Patrick Uiterwijk 7b9080
Patrick Uiterwijk 7b9080
    It should never be allowed to be called in production instances, since that
Patrick Uiterwijk 7b9080
    would allow an attacker to basically DOS a project by calling this
Patrick Uiterwijk 7b9080
    repeatedly. """
Pierre-Yves Chibon 9c2953
    assert pagure_config.get("ALLOW_PROJECT_DOWAIT", False)
Pierre-Yves Chibon f2db4b
Pierre-Yves Chibon 930073
    project = pagure.lib.query._get_project(
Pierre-Yves Chibon 9c2953
        session, namespace=namespace, name=name, user=user
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon edbdc9
Pierre-Yves Chibon 9c2953
    with project.lock("WORKER"):
Patrick Uiterwijk 7b9080
        time.sleep(10)
Patrick Uiterwijk 7b9080
Pierre-Yves Chibon b130e5
    return ret(
Pierre-Yves Chibon 9c2953
        "ui_ns.view_repo", repo=name, username=user, namespace=namespace
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon acd3eb
Pierre-Yves Chibon acd3eb
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("MEDIUM_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Slavek Kabrda efeaa6
def sync_pull_ref(self, session, name, namespace, user, requestid):
Pierre-Yves Chibon acd3eb
    """ Synchronize a pull/ reference from the content in the forked repo,
Pierre-Yves Chibon acd3eb
    allowing local checkout of the pull-request.
Pierre-Yves Chibon acd3eb
    """
Pierre-Yves Chibon 930073
    project = pagure.lib.query._get_project(
Pierre-Yves Chibon 9c2953
        session, namespace=namespace, name=name, user=user
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon acd3eb
Pierre-Yves Chibon 9c2953
    with project.lock("WORKER"):
Pierre-Yves Chibon 930073
        request = pagure.lib.query.search_pull_requests(
Pierre-Yves Chibon 9c2953
            session, project_id=project.id, requestid=requestid
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon acd3eb
        _log.debug(
Pierre-Yves Chibon 9c2953
            "Update pull refs of: %s#%s", request.project.fullname, request.id
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon acd3eb
Pierre-Yves Chibon acd3eb
        if request.remote:
Pierre-Yves Chibon acd3eb
            # Get the fork
Pierre-Yves Chibon b9d537
            repopath = pagure.utils.get_remote_repo_path(
Pierre-Yves Chibon 9c2953
                request.remote_git, request.branch_from
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon acd3eb
        else:
Pierre-Yves Chibon acd3eb
            # Get the fork
Pierre-Yves Chibon b130e5
            repopath = pagure.utils.get_repo_path(request.project_from)
Pierre-Yves Chibon 9c2953
        _log.debug("   working on the repo in: %s", repopath)
Pierre-Yves Chibon acd3eb
Pierre-Yves Chibon acd3eb
        repo_obj = pygit2.Repository(repopath)
Pierre-Yves Chibon acd3eb
        pagure.lib.git.update_pull_ref(request, repo_obj)
Pierre-Yves Chibon acd3eb
Pierre-Yves Chibon 36309a
Pierre-Yves Chibon 974201
@conn.task(queue=pagure_config.get("FAST_CELERY_QUEUE", None), bind=True)
Pierre-Yves Chibon 974201
@pagure_task
Pierre-Yves Chibon 974201
def update_pull_request(self, session, pr_uid):
Pierre-Yves Chibon 974201
    """ Updates a pull-request in the DB once a commit was pushed to it in
Pierre-Yves Chibon 974201
    git.
Pierre-Yves Chibon 974201
    """
Pierre-Yves Chibon 930073
    request = pagure.lib.query.get_request_by_uid(session, pr_uid)
Pierre-Yves Chibon 974201
Pierre-Yves Chibon 974201
    with request.project.lock("WORKER"):
Pierre-Yves Chibon 974201
Pierre-Yves Chibon 974201
        _log.debug(
Pierre-Yves Chibon 974201
            "Updating pull-request: %s#%s",
Pierre-Yves Chibon 974201
            request.project.fullname,
Pierre-Yves Chibon 974201
            request.id,
Pierre-Yves Chibon 974201
        )
Pierre-Yves Chibon 974201
        if request.remote:
Pierre-Yves Chibon 974201
            repopath = pagure.utils.get_remote_repo_path(
Pierre-Yves Chibon 974201
                request.remote_git, request.branch_from
Pierre-Yves Chibon 974201
            )
Pierre-Yves Chibon 974201
            parentpath = pagure.utils.get_repo_path(request.project)
Pierre-Yves Chibon 974201
        else:
Pierre-Yves Chibon 974201
            repo_from = request.project_from
Pierre-Yves Chibon 974201
            parentpath = pagure.utils.get_repo_path(request.project)
Pierre-Yves Chibon 974201
            repopath = parentpath
Pierre-Yves Chibon 974201
            if repo_from:
Pierre-Yves Chibon 974201
                repopath = pagure.utils.get_repo_path(repo_from)
Pierre-Yves Chibon b8cc62
        _log.debug(
Pierre-Yves Chibon b8cc62
            "   working on the repo in: %s and %s", repopath, parentpath
Pierre-Yves Chibon b8cc62
        )
Pierre-Yves Chibon 974201
Pierre-Yves Chibon 974201
        repo_obj = pygit2.Repository(repopath)
Pierre-Yves Chibon 974201
        orig_repo = pygit2.Repository(parentpath)
Pierre-Yves Chibon 974201
Pierre-Yves Chibon 974201
        pagure.lib.git.diff_pull_request(
Pierre-Yves Chibon 974201
            session, request, repo_obj, orig_repo, with_diff=False
Pierre-Yves Chibon 974201
        )
Pierre-Yves Chibon 974201
Pierre-Yves Chibon 974201
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("MEDIUM_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Slavek Kabrda efeaa6
def update_checksums_file(self, session, folder, filenames):
Pierre-Yves Chibon 314da3
    """ Update the checksums file in the release folder of the project.
Pierre-Yves Chibon 36309a
    """
Pierre-Yves Chibon f2db4b
Pierre-Yves Chibon 9c2953
    sha_file = os.path.join(folder, "CHECKSUMS")
Pierre-Yves Chibon 36309a
    new_file = not os.path.exists(sha_file)
Pierre-Yves Chibon 36309a
Pierre-Yves Chibon 36309a
    if not new_file:
Pierre-Yves Chibon 36309a
        with open(sha_file) as stream:
Pierre-Yves Chibon 36309a
            row = stream.readline().strip()
Pierre-Yves Chibon 9c2953
            if row != "# Generated and updated by pagure":
Pierre-Yves Chibon 36309a
                # This wasn't generated by pagure, don't touch it!
Pierre-Yves Chibon 36309a
                return
Pierre-Yves Chibon 36309a
Pierre-Yves Chibon 36309a
    for filename in filenames:
Pierre-Yves Chibon 9c2953
        algos = {"sha256": hashlib.sha256(), "sha512": hashlib.sha512()}
Pierre-Yves Chibon 36309a
        # for each files computes the different algorythm supported
Pierre-Yves Chibon 36309a
        with open(os.path.join(folder, filename), "rb") as stream:
Pierre-Yves Chibon 36309a
            while True:
Pierre-Yves Chibon 36309a
                buf = stream.read(2 * 2 ** 10)
Pierre-Yves Chibon 36309a
                if buf:
Pierre-Yves Chibon 36309a
                    for hasher in algos.values():
Pierre-Yves Chibon 36309a
                        hasher.update(buf)
Pierre-Yves Chibon 36309a
                else:
Pierre-Yves Chibon 36309a
                    break
Pierre-Yves Chibon 36309a
Pierre-Yves Chibon 36309a
        # Write them out to the output file
Pierre-Yves Chibon 9c2953
        with open(sha_file, "a") as stream:
Pierre-Yves Chibon 36309a
            if new_file:
Pierre-Yves Chibon 9c2953
                stream.write("# Generated and updated by pagure\n")
Pierre-Yves Chibon 4c06f0
                new_file = False
Aurélien Bompard f61bb3
            for algo in sorted(algos):
Pierre-Yves Chibon 9c2953
                stream.write(
Pierre-Yves Chibon 9c2953
                    "%s (%s) = %s\n"
Pierre-Yves Chibon 9c2953
                    % (algo.upper(), filename, algos[algo].hexdigest())
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 716362
Pierre-Yves Chibon 716362
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("FAST_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Slavek Kabrda efeaa6
def commits_author_stats(self, session, repopath):
Pierre-Yves Chibon 716362
    """ Returns some statistics about commits made against the specified
Pierre-Yves Chibon 716362
    git repository.
Pierre-Yves Chibon 716362
    """
Pierre-Yves Chibon f2db4b
Pierre-Yves Chibon 716362
    if not os.path.exists(repopath):
Pierre-Yves Chibon 9c2953
        raise ValueError("Git repository not found.")
Pierre-Yves Chibon 716362
Pierre-Yves Chibon 716362
    repo_obj = pygit2.Repository(repopath)
Pierre-Yves Chibon 716362
Pierre-Yves Chibon 716362
    stats = collections.defaultdict(int)
Lubomír Sedlář 444e6e
    number_of_commits = 0
Pierre-Yves Chibon 716362
    authors_email = set()
Pierre-Yves Chibon 716362
    for commit in repo_obj.walk(
Slavek Kabrda 0dd0cd
        repo_obj.head.get_object().oid.hex, pygit2.GIT_SORT_NONE
Pierre-Yves Chibon 9c2953
    ):
Lubomír Sedlář 444e6e
        # For each commit record how many times each combination of name and
Lubomír Sedlář 444e6e
        # e-mail appears in the git history.
Lubomír Sedlář 444e6e
        number_of_commits += 1
Pierre-Yves Chibon 716362
        email = commit.author.email
Pierre-Yves Chibon 716362
        author = commit.author.name
Pierre-Yves Chibon 716362
        stats[(author, email)] += 1
Pierre-Yves Chibon 716362
Pierre-Yves Chibon f2fe29
    for (name, email), val in list(stats.items()):
Lubomír Sedlář 4c386f
        if not email:
Lubomír Sedlář 4c386f
            # Author email is missing in the git commit.
Lubomír Sedlář 4c386f
            continue
Lubomír Sedlář 444e6e
        # For each recorded user info, check if we know the e-mail address of
Lubomír Sedlář 444e6e
        # the user.
Pierre-Yves Chibon 930073
        user = pagure.lib.query.search_user(session, email=email)
Lubomír Sedlář 444e6e
        if user and (user.default_email != email or user.fullname != name):
Lubomír Sedlář 444e6e
            # We know the the user, but the name or e-mail used in Git commit
Lubomír Sedlář 444e6e
            # does not match their default e-mail address and full name. Let's
Lubomír Sedlář 444e6e
            # merge them into one record.
Lubomír Sedlář 444e6e
            stats.pop((name, email))
Lubomír Sedlář 444e6e
            stats[(user.fullname, user.default_email)] += val
Lubomír Sedlář 444e6e
Lubomír Sedlář 444e6e
    # Generate a list of contributors ordered by how many commits they
Lubomír Sedlář 444e6e
    # authored. The list consists of tuples with number of commits and people
Lubomír Sedlář 444e6e
    # with that number of commits. Each contributor is represented by a name
Lubomír Sedlář 444e6e
    # and e-mail address.
Pierre-Yves Chibon 716362
    out_stats = collections.defaultdict(list)
Pierre-Yves Chibon 716362
    for authors, val in stats.items():
Lubomír Sedlář 444e6e
        authors_email.add(authors[1])
Pierre-Yves Chibon 716362
        out_stats[val].append(authors)
Pierre-Yves Chibon 609c2b
    out_list = [
Pierre-Yves Chibon 9c2953
        (key, out_stats[key]) for key in sorted(out_stats, reverse=True)
Pierre-Yves Chibon 609c2b
    ]
Pierre-Yves Chibon 716362
Lubomír Sedlář 444e6e
    return (
Lubomír Sedlář 444e6e
        number_of_commits,
Lubomír Sedlář 444e6e
        out_list,
Lubomír Sedlář 444e6e
        len(authors_email),
Pierre-Yves Chibon 9c2953
        commit.commit_time,
Lubomír Sedlář 444e6e
    )
Pierre-Yves Chibon 1828a2
Pierre-Yves Chibon 1828a2
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("FAST_CELERY_QUEUE", None), bind=True)
Slavek Kabrda efeaa6
@pagure_task
Slavek Kabrda efeaa6
def commits_history_stats(self, session, repopath):
Pierre-Yves Chibon 1828a2
    """ Returns the evolution of the commits made against the specified
Pierre-Yves Chibon 1828a2
    git repository.
Pierre-Yves Chibon 1828a2
    """
Pierre-Yves Chibon f2db4b
Pierre-Yves Chibon 1828a2
    if not os.path.exists(repopath):
Pierre-Yves Chibon 9c2953
        raise ValueError("Git repository not found.")
Pierre-Yves Chibon 1828a2
Pierre-Yves Chibon 1828a2
    repo_obj = pygit2.Repository(repopath)
Pierre-Yves Chibon 1828a2
Pierre-Yves Chibon 1828a2
    dates = collections.defaultdict(int)
Pierre-Yves Chibon 1828a2
    for commit in repo_obj.walk(
Slavek Kabrda 0dd0cd
        repo_obj.head.get_object().oid.hex, pygit2.GIT_SORT_NONE
Pierre-Yves Chibon 9c2953
    ):
Pierre-Yves Chibon 9c2953
        delta = (
Pierre-Yves Chibon 9c2953
            datetime.datetime.utcnow() - arrow.get(commit.commit_time).naive
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 1828a2
        if delta.days > 365:
Pierre-Yves Chibon 1828a2
            break
Pierre-Yves Chibon 1828a2
        dates[arrow.get(commit.commit_time).date().isoformat()] += 1
Pierre-Yves Chibon 1828a2
Pierre-Yves Chibon 1828a2
    return [(key, dates[key]) for key in sorted(dates)]
Pierre-Yves Chibon 11d019
Pierre-Yves Chibon 11d019
Pierre-Yves Chibon 9c2953
@conn.task(queue=pagure_config.get("MEDIUM_CELERY_QUEUE", None), bind=True)
Pierre-Yves Chibon 11d019
@pagure_task
Pierre-Yves Chibon 11d019
def link_pr_to_ticket(self, session, pr_uid):
Pierre-Yves Chibon 11d019
    """ Link the specified pull-request against the ticket(s) mentioned in
Pierre-Yves Chibon 11d019
    the commits of the pull-request
Pierre-Yves Chibon 11d019
Pierre-Yves Chibon 11d019
    """
Pierre-Yves Chibon 9c2953
    _log.info("LINK_PR_TO_TICKET: Linking ticket(s) to PR for: %s" % pr_uid)
Pierre-Yves Chibon 11d019
Pierre-Yves Chibon 930073
    request = pagure.lib.query.get_request_by_uid(session, pr_uid)
Pierre-Yves Chibon 11d019
    if not request:
Pierre-Yves Chibon 9c2953
        _log.info("LINK_PR_TO_TICKET: Not PR found for: %s" % pr_uid)
Pierre-Yves Chibon 11d019
        return
Pierre-Yves Chibon 11d019
Pierre-Yves Chibon 11d019
    if request.remote:
Pierre-Yves Chibon 11d019
        repopath = pagure.utils.get_remote_repo_path(
Pierre-Yves Chibon 9c2953
            request.remote_git, request.branch_from
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 11d019
        parentpath = pagure.utils.get_repo_path(request.project)
Pierre-Yves Chibon 11d019
    else:
Pierre-Yves Chibon 11d019
        repo_from = request.project_from
Pierre-Yves Chibon 11d019
        repopath = pagure.utils.get_repo_path(repo_from)
Pierre-Yves Chibon 11d019
        parentpath = get_parent_repo_path(repo_from)
Pierre-Yves Chibon 11d019
Pierre-Yves Chibon 11d019
    repo_obj = pygit2.Repository(repopath)
Pierre-Yves Chibon 11d019
    orig_repo = pygit2.Repository(parentpath)
Pierre-Yves Chibon 11d019
Pierre-Yves Chibon 11d019
    diff_commits = pagure.lib.git.diff_pull_request(
Pierre-Yves Chibon 35fe76
        session, request, repo_obj, orig_repo, with_diff=False, notify=False
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 11d019
Pierre-Yves Chibon 11d019
    _log.info(
Pierre-Yves Chibon 9c2953
        "LINK_PR_TO_TICKET: Found %s commits in that PR" % len(diff_commits)
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 11d019
Pierre-Yves Chibon 11d019
    name = request.project.name
Pierre-Yves Chibon 11d019
    namespace = request.project.namespace
Pierre-Yves Chibon 9c2953
    user = request.project.user.user if request.project.is_fork else None
Pierre-Yves Chibon 11d019
Pierre-Yves Chibon 11d019
    for line in pagure.lib.git.read_git_lines(
Pierre-Yves Chibon 9c2953
        ["log", "--no-walk"] + [c.oid.hex for c in diff_commits] + ["--"],
Pierre-Yves Chibon 9c2953
        repopath,
Pierre-Yves Chibon 9c2953
    ):
Pierre-Yves Chibon 11d019
Pierre-Yves Chibon 11d019
        line = line.strip()
Pierre-Yves Chibon 11d019
        for issue in pagure.lib.link.get_relation(
Pierre-Yves Chibon 9c2953
            session, name, user, namespace, line, "fixes", include_prs=False
Pierre-Yves Chibon 9c2953
        ):
Pierre-Yves Chibon 11d019
            _log.info(
Pierre-Yves Chibon 9c2953
                "LINK_PR_TO_TICKET: Link ticket %s to PRs %s"
Pierre-Yves Chibon 9c2953
                % (issue, request)
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 930073
            pagure.lib.query.link_pr_issue(session, issue, request)
Pierre-Yves Chibon 11d019
Pierre-Yves Chibon 11d019
        for issue in pagure.lib.link.get_relation(
Pierre-Yves Chibon 9c2953
            session, name, user, namespace, line, "relates"
Pierre-Yves Chibon 9c2953
        ):
Pierre-Yves Chibon 11d019
            _log.info(
Pierre-Yves Chibon 9c2953
                "LINK_PR_TO_TICKET: Link ticket %s to PRs %s"
Pierre-Yves Chibon 9c2953
                % (issue, request)
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 930073
            pagure.lib.query.link_pr_issue(session, issue, request)
Pierre-Yves Chibon 8584f3
Pierre-Yves Chibon 8584f3
    try:
Pierre-Yves Chibon 8584f3
        session.commit()
Pierre-Yves Chibon 8584f3
    except SQLAlchemyError:
Pierre-Yves Chibon 9c2953
        _log.exception("Could not link ticket to PR :(")
Pierre-Yves Chibon 8584f3
        session.rollback()
Karsten Hopp 0a3020
Karsten Hopp 0a3020
Karsten Hopp 0a3020
@conn.task(queue=pagure_config.get("MEDIUM_CELERY_QUEUE", None), bind=True)
Karsten Hopp 0a3020
@pagure_task
Karsten Hopp 0a3020
def pull_request_ready_branch(self, session, namespace, name, user):
Pierre-Yves Chibon 930073
    repo = pagure.lib.query._get_project(
Karsten Hopp 0a3020
        session, name, user=user, namespace=namespace
Karsten Hopp 0a3020
    )
Karsten Hopp 0a3020
    repo_obj = pygit2.Repository(pagure.utils.get_repo_path(repo))
Karsten Hopp 0a3020
Karsten Hopp 0a3020
    if repo.is_fork and repo.parent:
Karsten Hopp 0a3020
        parentreponame = pagure.utils.get_repo_path(repo.parent)
Karsten Hopp 0a3020
        parent_repo_obj = pygit2.Repository(parentreponame)
Karsten Hopp 0a3020
    else:
Karsten Hopp 0a3020
        parent_repo_obj = repo_obj
Karsten Hopp 0a3020
Karsten Hopp 0a3020
    branches = {}
Karsten Hopp 0a3020
    if not repo_obj.is_empty and len(repo_obj.listall_branches()) > 0:
Karsten Hopp 0a3020
        for branchname in repo_obj.listall_branches():
Karsten Hopp 0a3020
            compare_branch = None
Karsten Hopp 0a3020
            if (
Karsten Hopp 0a3020
                not parent_repo_obj.is_empty
Karsten Hopp 0a3020
                and not parent_repo_obj.head_is_unborn
Karsten Hopp 0a3020
            ):
Karsten Hopp 0a3020
                try:
Karsten Hopp 0a3020
                    if pagure.config.config.get(
Karsten Hopp 0a3020
                        "PR_TARGET_MATCHING_BRANCH", False
Karsten Hopp 0a3020
                    ):
Karsten Hopp 0a3020
                        # find parent branch which is the longest substring of
Karsten Hopp 0a3020
                        # branch that we're processing
Karsten Hopp 0a3020
                        compare_branch = ""
Karsten Hopp 0a3020
                        for parent_branch in parent_repo_obj.branches:
Karsten Hopp 0a3020
                            if (
Karsten Hopp 0a3020
                                not repo.is_fork
Karsten Hopp 0a3020
                                and branchname == parent_branch
Karsten Hopp 0a3020
                            ):
Karsten Hopp 0a3020
                                continue
Karsten Hopp 0a3020
                            if branchname.startswith(parent_branch) and len(
Karsten Hopp 0a3020
                                parent_branch
Karsten Hopp 0a3020
                            ) > len(compare_branch):
Karsten Hopp 0a3020
                                compare_branch = parent_branch
Karsten Hopp 0a3020
                        compare_branch = (
Karsten Hopp 0a3020
                            compare_branch or repo_obj.head.shorthand
Karsten Hopp 0a3020
                        )
Karsten Hopp 0a3020
                    else:
Karsten Hopp 0a3020
                        compare_branch = repo_obj.head.shorthand
Karsten Hopp 0a3020
                except pygit2.GitError:
Karsten Hopp 0a3020
                    pass  # let compare_branch be None
Karsten Hopp 0a3020
Karsten Hopp 0a3020
            # Do not compare a branch to itself
Karsten Hopp 0a3020
            if (
Karsten Hopp 0a3020
                not repo.is_fork
Karsten Hopp 0a3020
                and compare_branch
Karsten Hopp 0a3020
                and compare_branch == branchname
Karsten Hopp 0a3020
            ):
Karsten Hopp 0a3020
                continue
Karsten Hopp 0a3020
Karsten Hopp 0a3020
            diff_commits = None
Karsten Hopp 0a3020
            try:
Karsten Hopp 0a3020
                _, diff_commits, _ = pagure.lib.git.get_diff_info(
Karsten Hopp 0a3020
                    repo_obj, parent_repo_obj, branchname, compare_branch
Karsten Hopp 0a3020
                )
Karsten Hopp 0a3020
            except pagure.exceptions.PagureException:
Karsten Hopp 0a3020
                pass
Karsten Hopp 0a3020
Karsten Hopp 0a3020
            if diff_commits:
Karsten Hopp 0a3020
                branches[branchname] = {
Karsten Hopp 0a3020
                    "commits": len(list(diff_commits)),
Karsten Hopp 0a3020
                    "target_branch": compare_branch or "master",
Karsten Hopp 0a3020
                }
Karsten Hopp 0a3020
Pierre-Yves Chibon 930073
    prs = pagure.lib.query.search_pull_requests(
Karsten Hopp 0a3020
        session, project_id_from=repo.id, status="Open"
Karsten Hopp 0a3020
    )
Karsten Hopp 0a3020
    branches_pr = {}
Karsten Hopp 0a3020
    for pr in prs:
Karsten Hopp 0a3020
        if pr.branch_from in branches:
Karsten Hopp 0a3020
            branches_pr[pr.branch_from] = "%s/pull-request/%s" % (
Karsten Hopp 0a3020
                pr.project.url_path,
Karsten Hopp 0a3020
                pr.id,
Karsten Hopp 0a3020
            )
Karsten Hopp 0a3020
            del (branches[pr.branch_from])
Karsten Hopp 0a3020
    return {"new_branch": branches, "branch_w_pr": branches_pr}