From 5afad495ece7602056594e42647b55d0bd395508 Mon Sep 17 00:00:00 2001
From: Slavek Kabrda <bkabrda@redhat.com>
Date: May 14 2018 13:38:09 +0000
Subject: Add a hook that disables creating new branches by pushing


---

diff --git a/alembic/versions/131ad2dc5bbd_table_for_no_new_branches_hook.py b/alembic/versions/131ad2dc5bbd_table_for_no_new_branches_hook.py
new file mode 100644
index 0000000..4ca7659
--- /dev/null
+++ b/alembic/versions/131ad2dc5bbd_table_for_no_new_branches_hook.py
@@ -0,0 +1,38 @@
+"""Table for no new branches hook
+
+Revision ID: 131ad2dc5bbd
+Revises: 7f31a9fad89f
+Create Date: 2018-05-11 10:52:05.088806
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '131ad2dc5bbd'
+down_revision = '7f31a9fad89f'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+    """ Create table for PagureNoNewBranchesHook. """
+    op.create_table(
+        'hook_pagure_no_new_branches',
+        sa.Column('id', sa.INTEGER(), nullable=False),
+        sa.Column('project_id', sa.INTEGER(), nullable=False),
+        sa.Column('active', sa.BOOLEAN(), nullable=False),
+        sa.CheckConstraint(u'active IN (0, 1)'),
+        sa.ForeignKeyConstraint(
+            ['project_id'],
+            [u'projects.id'],
+            name=u'hook_pagure_no_new_branches_project_id_fkey',
+            onupdate=u'CASCADE',
+            ondelete=u'CASCADE'
+        ),
+        sa.PrimaryKeyConstraint('id', name=u'hook_pagure_no_new_branches_pkey')
+    )
+
+
+def downgrade():
+    """ Remove table for PagureNoNewBranchesHook. """
+    op.drop_table('hook_pagure_no_new_branches')
diff --git a/pagure/hooks/files/pagure_no_new_branches b/pagure/hooks/files/pagure_no_new_branches
new file mode 100755
index 0000000..759c9c4
--- /dev/null
+++ b/pagure/hooks/files/pagure_no_new_branches
@@ -0,0 +1,12 @@
+#!/bin/bash
+# adapted from https://stackoverflow.com/a/29880516
+
+retcode=0
+while read -r old new refname; do
+    if [[ $refname == refs/heads/* && $old != *[^0]* ]]; then
+        retcode=1
+        echo "Creating new branches is disabled on this project."
+    fi
+done
+
+exit $retcode
diff --git a/pagure/hooks/pagure_no_new_branches.py b/pagure/hooks/pagure_no_new_branches.py
new file mode 100644
index 0000000..a8a929d
--- /dev/null
+++ b/pagure/hooks/pagure_no_new_branches.py
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+
+"""
+ (c) 2014-2018 - Copyright Red Hat Inc
+
+ Authors:
+   Slavek Kabrda <bkabrda@redhat.com>
+
+"""
+
+from __future__ import unicode_literals
+
+import os
+
+import sqlalchemy as sa
+import wtforms
+try:
+    from flask_wtf import FlaskForm
+except ImportError:
+    from flask_wtf import Form as FlaskForm
+from sqlalchemy.orm import relation
+from sqlalchemy.orm import backref
+
+from pagure.hooks import BaseHook
+from pagure.lib.model import BASE, Project
+from pagure.utils import get_repo_path
+
+
+class PagureNoNewBranchesTable(BASE):
+    """ Stores information about the pagure hook deployed on a project.
+
+    Table -- hook_pagure_no_new_branches
+    """
+
+    __tablename__ = 'hook_pagure_no_new_branches'
+
+    id = sa.Column(sa.Integer, primary_key=True)
+    project_id = sa.Column(
+        sa.Integer,
+        sa.ForeignKey(
+            'projects.id', onupdate='CASCADE', ondelete='CASCADE'),
+        nullable=False,
+        unique=True,
+        index=True)
+
+    active = sa.Column(sa.Boolean, nullable=False, default=False)
+
+    project = relation(
+        'Project', remote_side=[Project.id],
+        backref=backref(
+            'pagure_hook_no_new_branches',
+            cascade="delete, delete-orphan",
+            single_parent=True, uselist=False)
+    )
+
+
+class PagureNoNewBranchesForm(FlaskForm):
+    ''' Form to configure the pagure hook. '''
+    active = wtforms.BooleanField(
+        'Active',
+        [wtforms.validators.Optional()]
+    )
+
+
+class PagureNoNewBranchesHook(BaseHook):
+    ''' PagureNoNewBranches hook. '''
+
+    name = 'Prevent creating new branches by git push'
+    description = 'This hook prevents creating new branches by git push.'
+    form = PagureNoNewBranchesForm
+    db_object = PagureNoNewBranchesTable
+    backref = 'pagure_hook_no_new_branches'
+    form_fields = ['active']
+    hook_type = 'pre-receive'
+
+    @classmethod
+    def install(cls, project, dbobj):
+        ''' Method called to install the hook for a project.
+
+        :arg project: a ``pagure.model.Project`` object to which the hook
+            should be installed
+
+        '''
+        repopaths = [get_repo_path(project)]
+
+        cls.base_install(repopaths, dbobj, 'pagure_no_new_branches',
+                         'pagure_no_new_branches')
+
+    @classmethod
+    def remove(cls, project):
+        ''' Method called to remove the hook of a project.
+
+        :arg project: a ``pagure.model.Project`` object to which the hook
+            should be installed
+
+        '''
+        cls.base_remove(repopaths, 'pagure_no_new_branches')

