David Caro has uploaded a new change for review.

Change subject: Added first python hooks and libs
......................................................................

Added first python hooks and libs

* Added basic config.py lib
* Added basic gerrit.py lib
* Added hook to check if the patch is merged on all newer branches

Change-Id: I985113f5a228ccc128eaad3dbf45c918b7fc093a
Signed-off-by: David Caro <[email protected]>
---
A hooks/bz/patchset-created.warn_if_not_merged_to_previous_branch
M hooks/hook-dispatcher
A hooks/lib/config.py
A hooks/lib/config.pyc
A hooks/lib/gerrit.py
A hooks/lib/gerrit.pyc
6 files changed, 231 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.ovirt.org:29418/gerrit-admin refs/changes/08/24208/1

diff --git a/hooks/bz/patchset-created.warn_if_not_merged_to_previous_branch 
b/hooks/bz/patchset-created.warn_if_not_merged_to_previous_branch
new file mode 100755
index 0000000..20b035d
--- /dev/null
+++ b/hooks/bz/patchset-created.warn_if_not_merged_to_previous_branch
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+
+import argparse
+import logging
+import sys
+import os
+from config import load_config
+from gerrit import Gerrit
+
+
+def is_newer(branch1, branch2):
+    try:
+        b1_ver_num = branch1.rsplit('-', 1)[1]
+        b2_ver_num = branch2.rsplit('-', 1)[1]
+        b1_tuple = tuple(map(int, (b1_ver_num.split("."))))
+        b2_tuple = tuple(map(int, (b2_ver_num.split("."))))
+    except (IndexError, ValueError):
+        raise Exception("Unable to parse version strings (%s, %s)"
+                        % (branch1, branch2))
+    return b1_tuple > b2_tuple
+
+
+def get_unmerged_newer_branches(gerrit, change_id, cur_branch):
+    branches = []
+    patches = gerrit.query(change_id, out_format='json')
+    for patch in patches:
+        if 'branch' not in patch:
+            continue
+        logging.debug("Checking patch %s" % str(patch))
+        if is_newer(patch['branch'], cur_branch) and patch['open']:
+            logging.error('patch with id {id} still open for branch '
+                          '{branch}'.format(**patch))
+            branches.append(patch['branch'])
+    return branches
+
+
+def get_parser():
+    """
+    Build the parser for patchset-created hook type
+    """
+    parser = argparse.ArgumentParser(
+        description=('This dispatcher handles the'
+                     ' special tags and hook'
+                     ' execution'),
+    )
+    for arg in ('change', 'project', 'branch', 'commit', 'is-draft',
+                'change-url', 'author', 'comment'):
+        parser.add_argument('--' + arg,
+                            action='store',
+                            required=True)
+    parser.add_argument('-v', '--verbose', action='store_true', default=False)
+    return parser
+
+
+def give_warning(gerrit, commit, project, branches):
+    msg = ("WARNING: This patch was not merged yet on all the newer "
+           "branches\n  Missing on: %s" % ', '.join(branches))
+    gerrit.review(commit=commit, project=project, message=msg)
+
+
+def main():
+    parser = get_parser()
+    args = parser.parse_args()
+    if args.verbose:
+        loglevel = logging.DEBUG
+    else:
+        loglevel = logging.INFO
+    logging.basicConfig(stream=sys.stdout,
+                        level=loglevel,
+                        format='%(asctime)s::'
+                        + str(os.getpid())
+                        + '::%(levelname)s::%(message)s')
+    config = load_config()
+    logging.debug("STARTING::PARAMS %s" % sys.argv)
+    gerrit = Gerrit(config['GERRIT_SRV'])
+    unmerged_branches = get_unmerged_newer_branches(
+        gerrit,
+        args.change,
+        args.branch)
+    if unmerged_branches:
+        give_warning(gerrit, args.commit, args.project, unmerged_branches)
+    logging.info("FINISHED")
+
+
+if __name__ == '__main__':
+    main()
diff --git a/hooks/hook-dispatcher b/hooks/hook-dispatcher
index 93595f9..fc09c76 100755
--- a/hooks/hook-dispatcher
+++ b/hooks/hook-dispatcher
@@ -235,6 +235,8 @@
     ## add the hooks lib dir to the path
     os.environ["PATH"] = os.environ["PATH"] + ':' \
         + os.path.dirname(os.path.realpath(__file__)) + '/lib'
+    os.environ["PYTHONPATH"] = os.environ.get("PYTHONPATH", "") \
+       + ':' + os.path.dirname(os.path.realpath(__file__)) + '/lib'
     hooks.sort()
     params = sys.argv[1:]
     for hook in hooks:
@@ -297,7 +299,7 @@
 def main():
     logpath = os.path.join(os.path.dirname(__file__), '..', 'logs')
     logging.basicConfig(filename=os.path.join(logpath, 'gerrit.hooks.log'),
-                        level=logging.INFO,
+                        level=logging.DEBUG,
                         format='%(asctime)s::'
                         + str(os.getpid())
                         + '::%(levelname)s::%(message)s')
diff --git a/hooks/lib/config.py b/hooks/lib/config.py
new file mode 100644
index 0000000..5d28a17
--- /dev/null
+++ b/hooks/lib/config.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+#encoding: utf-8
+import re
+import os
+from os.path import (
+    abspath,
+    dirname,
+    join as pjoin,
+    exists as fexists,
+)
+import logging
+
+
+logger = logging.getLogger(__name__)
+
+
+CONF_FILES = [
+    pjoin(dirname(abspath(__file__)), '..', 'config'),
+    pjoin(os.environ.get('GIT_DIR', ''), 'hooks', 'config'),
+]
+
+
+def unquote(string):
+    if re.match(r'^(\'|").*', string):
+        return string[1:-1]
+    else:
+        return string
+
+
+class Config(dict):
+    def __init__(self, files=None):
+        files = files or []
+        self.files = []
+        for fname in files:
+            if not fname:
+                continue
+            if fexists(fname):
+                self.read(fname)
+            else:
+                logger.warn('Unable to read config file %s' % fname)
+
+    def read(self, filename):
+        linenum = 0
+        for line in open(filename, 'r'):
+            if not line.strip() or line.strip().startswith('#'):
+                continue
+            if '=' not in line:
+                logger.warn('Malformed config entry at %s line %d :\n%s'
+                            % (filename, linenum, line))
+            key, val = map(lambda x: unquote(str.strip(x)),
+                           line.split('=', 1))
+            self[key] = val
+            linenum += 1
+        self.files.append(filename)
+
+    def __getitem__(self, item):
+        try:
+            return dict.__getitem__(self, item)
+        except KeyError:
+            logger.error('Unable to get config value %s from any of the '
+                         'config files [%s]' % (item,', '.join(self.files)))
+            raise
+
+
+def load_config():
+    return Config(CONF_FILES)
diff --git a/hooks/lib/config.pyc b/hooks/lib/config.pyc
new file mode 100644
index 0000000..e7a6f0f
--- /dev/null
+++ b/hooks/lib/config.pyc
Binary files differ
diff --git a/hooks/lib/gerrit.py b/hooks/lib/gerrit.py
new file mode 100644
index 0000000..3b09a42
--- /dev/null
+++ b/hooks/lib/gerrit.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+#encoding: utf-8
+import subprocess
+import json
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+class Gerrit(object):
+    def __init__(self, server):
+        self.server = server
+        self.cmd = (
+            'ssh',
+            '-o', 'UserKnownHostsFile=/dev/null',
+            '-o', 'StrictHostKeyChecking=no',
+            self.server,
+            '-p', '29418',
+            'gerrit',
+        )
+
+    def generate_cmd(self, action, *options):
+        cmd =  list(self.cmd)
+        cmd.append(action)
+        cmd.extend(options)
+        return cmd
+
+    def review(self, commit, message, project, verify=None, review=None):
+        gerrit_cmd = self.generate_cmd(
+            'review',
+            commit,
+            '--message="%s"' % message,
+            '--project=%s' % project,
+        )
+        if verify is not None:
+            gerrit_cmd.append('--verify=%s' % str(verify))
+        if review is not None:
+            gerrit_cmd.append('--code-review=%s' % str(review))
+        cmd = subprocess.Popen(gerrit_cmd,
+                            stdout=subprocess.PIPE,
+                            stderr=subprocess.PIPE)
+        out, err = cmd.communicate()
+        if cmd.returncode:
+            raise Exception("Execution of %s returned %d:\n%s"
+                            % (' '.join(gerrit_cmd),
+                                cmd.returncode,
+                                err))
+        return 0
+
+    def query(self, query, out_format='json'):
+        gerrit_cmd = self.generate_cmd(
+            'query',
+            '--format=%s' % out_format,
+            query,
+        )
+        logger.debug("Executing %s" % ' '.join(gerrit_cmd))
+        cmd = subprocess.Popen(gerrit_cmd,
+                            stdout=subprocess.PIPE,
+                            stderr=subprocess.PIPE)
+        out, err = cmd.communicate()
+        if cmd.returncode:
+            raise Exception("Execution of %s returned %d:\n%s"
+                            % (' '.join(gerrit_cmd),
+                                cmd.returncode,
+                                err))
+        if out_format == 'json':
+            res = []
+            try:
+                for line in out.splitlines():
+                    res.append(json.loads(line))
+            except ValueError:
+                logger.error("Unable to decode json from:\n%s" % line)
+                raise
+        else:
+            res = out
+        return res
diff --git a/hooks/lib/gerrit.pyc b/hooks/lib/gerrit.pyc
new file mode 100644
index 0000000..9f762aa
--- /dev/null
+++ b/hooks/lib/gerrit.pyc
Binary files differ


-- 
To view, visit http://gerrit.ovirt.org/24208
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I985113f5a228ccc128eaad3dbf45c918b7fc093a
Gerrit-PatchSet: 1
Gerrit-Project: gerrit-admin
Gerrit-Branch: master
Gerrit-Owner: David Caro <[email protected]>
_______________________________________________
Engine-patches mailing list
[email protected]
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to