Blame pagure/hooks/pagure_ticket_hook.py

Pierre-Yves Chibon 33b534
# -*- coding: utf-8 -*-
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 1d6d27
"""
Pierre-Yves Chibon 2c3a3f
 (c) 2014-2016 - Copyright Red Hat Inc
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 1d6d27
 Authors:
Pierre-Yves Chibon 1d6d27
   Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 1d6d27
"""
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 67d1cc
from __future__ import unicode_literals, absolute_import
Aurélien Bompard dcf6f6
Pierre-Yves Chibon 1d6d27
import os
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 1d6d27
import sqlalchemy as sa
Pierre-Yves Chibon 1d6d27
import wtforms
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon 5a5352
try:
Pierre-Yves Chibon 2011e2
    from flask_wtf import FlaskForm
Pierre-Yves Chibon 5a5352
except ImportError:
Pierre-Yves Chibon 5a5352
    from flask_wtf import Form as FlaskForm
Pierre-Yves Chibon 1d6d27
from sqlalchemy.orm import relation
Pierre-Yves Chibon 848b42
from sqlalchemy.orm import backref
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 930073
import pagure.lib.git
Pierre-Yves Chibon 930073
import pagure.lib.tasks_services
Pierre-Yves Chibon b130e5
from pagure.config import config as pagure_config
Pierre-Yves Chibon a8e1a6
from pagure.exceptions import FileNotFoundException
Pierre-Yves Chibon 0cae8b
from pagure.hooks import BaseHook, BaseRunner
Pierre-Yves Chibon fe5017
from pagure.lib.model import BASE, Project
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon fe5017
class PagureTicketsTable(BASE):
Pierre-Yves Chibon fe5017
    """ Stores information about the pagure tickets hook deployed on a project.
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon fe5017
    Table -- hook_pagure_tickets
Pierre-Yves Chibon 1d6d27
    """
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 9c2953
    __tablename__ = "hook_pagure_tickets"
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 1d6d27
    id = sa.Column(sa.Integer, primary_key=True)
Pierre-Yves Chibon 1d6d27
    project_id = sa.Column(
Pierre-Yves Chibon 1d6d27
        sa.Integer,
Pierre-Yves Chibon 9c2953
        sa.ForeignKey("projects.id", onupdate="CASCADE", ondelete="CASCADE"),
Pierre-Yves Chibon 1d6d27
        nullable=False,
Pierre-Yves Chibon 1d6d27
        unique=True,
Pierre-Yves Chibon 9c2953
        index=True,
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 1d6d27
    active = sa.Column(sa.Boolean, nullable=False, default=False)
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 1d6d27
    project = relation(
Pierre-Yves Chibon 9c2953
        "Project",
Pierre-Yves Chibon 9c2953
        remote_side=[Project.id],
Pierre-Yves Chibon 848b42
        backref=backref(
Pierre-Yves Chibon 9c2953
            "pagure_hook_tickets",
Pierre-Yves Chibon 9c2953
            cascade="delete, delete-orphan",
Pierre-Yves Chibon 9c2953
            single_parent=True,
Pierre-Yves Chibon 9c2953
            uselist=False,
Pierre-Yves Chibon 9c2953
        ),
farhaanbukhsh 9b97b4
    )
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 0cae8b
class PagureTicketRunner(BaseRunner):
Pierre-Yves Chibon 0cae8b
    """ Runner for the git hook updating the DB of tickets on push. """
Pierre-Yves Chibon 0cae8b
Pierre-Yves Chibon 0cae8b
    @staticmethod
Patrick Uiterwijk 50c123
    def post_receive(session, username, project, repotype, repodir, changes):
Patrick Uiterwijk 50c123
        """ Run the post-receive tasks of a hook.
Pierre-Yves Chibon 0cae8b
Pierre-Yves Chibon 0cae8b
        For args, see BaseRunner.runhook.
Pierre-Yves Chibon 0cae8b
        """
Pierre-Yves Chibon 0cae8b
Pierre-Yves Chibon 0cae8b
        if repotype != "tickets":
Pierre-Yves Chibon 0cae8b
            print("The ticket hook only runs on the ticket git repository.")
Pierre-Yves Chibon 0cae8b
            return
Pierre-Yves Chibon 0cae8b
Patrick Uiterwijk 14dd1d
        if username == "pagure":
Patrick Uiterwijk 14dd1d
            # This was an update from inside the UI. Do not trigger further
Patrick Uiterwijk 14dd1d
            # database updates, as this has already been done
Patrick Uiterwijk 14dd1d
            return
Patrick Uiterwijk 14dd1d
Pierre-Yves Chibon 0cae8b
        for refname in changes:
Pierre-Yves Chibon 0cae8b
            (oldrev, newrev) = changes[refname]
Pierre-Yves Chibon 0cae8b
Pierre-Yves Chibon 0cae8b
            if set(newrev) == set(["0"]):
Pierre-Yves Chibon 0cae8b
                print(
Pierre-Yves Chibon 0cae8b
                    "Deleting a reference/branch, so we won't run the "
Pierre-Yves Chibon 0cae8b
                    "pagure hook"
Pierre-Yves Chibon 0cae8b
                )
Pierre-Yves Chibon 0cae8b
                return
Pierre-Yves Chibon 0cae8b
Pierre-Yves Chibon 0cae8b
            commits = pagure.lib.git.get_revs_between(
Pierre-Yves Chibon 0cae8b
                oldrev, newrev, repodir, refname
Pierre-Yves Chibon 0cae8b
            )
Pierre-Yves Chibon 0cae8b
Pierre-Yves Chibon 0cae8b
            pagure.lib.tasks_services.load_json_commits_to_db.delay(
Pierre-Yves Chibon 0cae8b
                name=project.name,
Pierre-Yves Chibon 0cae8b
                commits=commits,
Pierre-Yves Chibon 0cae8b
                abspath=repodir,
Pierre-Yves Chibon 0cae8b
                data_type="ticket",
Pierre-Yves Chibon 0cae8b
                agent=username,
Pierre-Yves Chibon 0cae8b
                namespace=project.namespace,
Pierre-Yves Chibon 0cae8b
                username=project.user.user if project.is_fork else None,
Pierre-Yves Chibon 0cae8b
            )
Pierre-Yves Chibon 0cae8b
Pierre-Yves Chibon 0cae8b
Pierre-Yves Chibon 5a5352
class PagureTicketsForm(FlaskForm):
Pierre-Yves Chibon 9c2953
    """ Form to configure the pagure hook. """
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon 9c2953
    active = wtforms.BooleanField("Active", [wtforms.validators.Optional()])
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon fe5017
class PagureTicketHook(BaseHook):
Pierre-Yves Chibon 9c2953
    """ Pagure ticket hook. """
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 9c2953
    name = "Pagure tickets"
Pierre-Yves Chibon 9c2953
    description = (
Pierre-Yves Chibon 9c2953
        "Pagure specific hook to update tickets stored in the "
Pierre-Yves Chibon 9c2953
        "database based on the information pushed in the tickets git "
Pierre-Yves Chibon 9c2953
        "repository."
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon fe5017
    form = PagureTicketsForm
Pierre-Yves Chibon fe5017
    db_object = PagureTicketsTable
Pierre-Yves Chibon 9c2953
    backref = "pagure_hook_tickets"
Pierre-Yves Chibon 9c2953
    form_fields = ["active"]
Pierre-Yves Chibon 0cae8b
    runner = PagureTicketRunner
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 1d6d27
    @classmethod
Pierre-Yves Chibon eab92f
    def set_up(cls, project):
Pierre-Yves Chibon 9c2953
        """ Install the generic post-receive hook that allow us to call
Pierre-Yves Chibon eab92f
        multiple post-receive hooks as set per plugin.
Pierre-Yves Chibon 9c2953
        """
Pierre-Yves Chibon 9c2953
        repopath = os.path.join(pagure_config["TICKETS_FOLDER"], project.path)
Pierre-Yves Chibon eab92f
        if not os.path.exists(repopath):
Pierre-Yves Chibon ee649a
            raise FileNotFoundException("No such file: %s" % repopath)
Pierre-Yves Chibon eab92f
Pierre-Yves Chibon eab92f
        hook_files = os.path.join(
Pierre-Yves Chibon 9c2953
            os.path.dirname(os.path.realpath(__file__)), "files"
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon eab92f
Pierre-Yves Chibon eab92f
        # Make sure the hooks folder exists
Pierre-Yves Chibon 9c2953
        hookfolder = os.path.join(repopath, "hooks")
Pierre-Yves Chibon eab92f
        if not os.path.exists(hookfolder):
Pierre-Yves Chibon eab92f
            os.makedirs(hookfolder)
Pierre-Yves Chibon eab92f
Pierre-Yves Chibon eab92f
        # Install the main post-receive file
Pierre-Yves Chibon 9c2953
        postreceive = os.path.join(hookfolder, "post-receive")
Pierre-Yves Chibon 9c2953
        hook_file = os.path.join(hook_files, "post-receive")
Pierre-Yves Chibon c106de
        if not os.path.exists(postreceive):
Pierre-Yves Chibon 6b3d22
            os.symlink(hook_file, postreceive)
Pierre-Yves Chibon eab92f
Pierre-Yves Chibon eab92f
    @classmethod
Pierre-Yves Chibon 1d6d27
    def install(cls, project, dbobj):
Pierre-Yves Chibon 9c2953
        """ Method called to install the hook for a project.
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon fe5017
        :arg project: a ``pagure.model.Project`` object to which the hook
Pierre-Yves Chibon 1d6d27
            should be installed
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 9c2953
        """
Pierre-Yves Chibon 9c2953
        repopaths = [
Pierre-Yves Chibon 9c2953
            os.path.join(pagure_config["TICKETS_FOLDER"], project.path)
Pierre-Yves Chibon 9c2953
        ]
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 9c2953
        cls.base_install(
Pierre-Yves Chibon 9c2953
            repopaths, dbobj, "pagure-ticket", "pagure_hook_tickets.py"
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 1d6d27
    @classmethod
Pierre-Yves Chibon 1d6d27
    def remove(cls, project):
Pierre-Yves Chibon 9c2953
        """ Method called to remove the hook of a project.
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon fe5017
        :arg project: a ``pagure.model.Project`` object to which the hook
Pierre-Yves Chibon 1d6d27
            should be installed
Pierre-Yves Chibon 1d6d27
Pierre-Yves Chibon 9c2953
        """
Pierre-Yves Chibon 9c2953
        repopaths = [
Pierre-Yves Chibon 9c2953
            os.path.join(pagure_config["TICKETS_FOLDER"], project.path)
Pierre-Yves Chibon 9c2953
        ]
Pierre-Yves Chibon 068919
Pierre-Yves Chibon 9c2953
        cls.base_remove(repopaths, "pagure-ticket")