Patchwork New hook to update patch status on pull

login
register
mail settings
Submitter Simo Sorce
Date March 23, 2013, 7:38 p.m.
Message ID <514E04A0.6030200@samba.org>
Download mbox | patch
Permalink /patch/230341/
State Rejected
Headers show

Comments

Simo Sorce - March 23, 2013, 7:38 p.m.
In my setup I do not want to hook patchwork directly in the upstream 
master tree as I do not have access to it.

So I created this patch that will update the status of patches after a pull.

It adds some code in utils.py to performthe actual update and a 
post-merge hook that is called when my cron job does a git pull from master.

I have briefly tested this in a staging server, and will deploy on my 
site shortly.

HTH,
Simo.
Jeremy Kerr - April 2, 2013, 11:24 a.m.
Hi Simo,

Thanks for the contribution :)

> In my setup I do not want to hook patchwork directly in the upstream
> master tree as I do not have access to it.
>
> So I created this patch that will update the status of patches after a
> pull.

Not meaning to be critical here, but is there a reason you don't want to 
use the existing scripts to do this, via the XMLRPC API?

> It adds some code in utils.py to performthe actual update and a
> post-merge hook that is called when my cron job does a git pull from
> master.

I'd prefer that we don't add the main function to utils.py, but instead 
create a new script for this.

Cheers,


Jeremy
Simo Sorce - April 2, 2013, 11:54 a.m.
On 04/02/2013 07:24 AM, Jeremy Kerr wrote:
> Hi Simo,
>
> Thanks for the contribution :)
>
>> In my setup I do not want to hook patchwork directly in the upstream
>> master tree as I do not have access to it.
>>
>> So I created this patch that will update the status of patches after a
>> pull.
>
> Not meaning to be critical here, but is there a reason you don't want 
> to use the existing scripts to do this, via the XMLRPC API?

The current scripts rely on the fact you can install hooks on the master 
tree everybody pushes to.
I cannot do that, I instead have a clone on the patchwork host and do 
cronjobed pulls. The post-merge hook is then used to analyse the pulled 
change-sets.

>> It adds some code in utils.py to performthe actual update and a
>> post-merge hook that is called when my cron job does a git pull from
>> master.
>
> I'd prefer that we don't add the main function to utils.py, but 
> instead create a new script for this.

Ok, I'll send a new patch with the function split out, any preference on 
the destination file name ?

Simo.
Jeremy Kerr - April 2, 2013, 1:37 p.m.
Hi Simo,

> The current scripts rely on the fact you can install hooks on the master
> tree everybody pushes to.
> I cannot do that, I instead have a clone on the patchwork host and do
> cronjobed pulls. The post-merge hook is then used to analyse the pulled
> change-sets.

No, they don't require any hooks on the master tree. IIRC, most project 
maintainers using patchwork simply run a script on their local checkout 
to update the patchwork states.

In your case, I'd suggest a cron job to do a git fetch from the main 
repo, and run tools/update-patchwork-commits (or a similar script) to 
update the state of patches added since the previous fetch.

Cheers,


Jeremy
Simo Sorce - April 2, 2013, 2:27 p.m.
On 04/02/2013 09:37 AM, Jeremy Kerr wrote:
> Hi Simo,
>
>> The current scripts rely on the fact you can install hooks on the master
>> tree everybody pushes to.
>> I cannot do that, I instead have a clone on the patchwork host and do
>> cronjobed pulls. The post-merge hook is then used to analyse the pulled
>> change-sets.
>
> No, they don't require any hooks on the master tree. IIRC, most 
> project maintainers using patchwork simply run a script on their local 
> checkout to update the patchwork states.
>
> In your case, I'd suggest a cron job to do a git fetch from the main 
> repo, and run tools/update-patchwork-commits (or a similar script) to 
> update the state of patches added since the previous fetch.

Ok, I guess I can retire the patch then.

Simo.

Patch

From 8767da729516725120027f37f65436e26137e45f Mon Sep 17 00:00:00 2001
From: Simo Sorce <idra@samba.org>
Date: Sat, 23 Mar 2013 14:40:00 -0400
Subject: [PATCH] Add post-merge tool to update git tree

In some cases it is not possible to add hooks to the master
tree however it is possible to easily pull from it into the
patchwork server.

This post-merge hook allows to mark patch status on pull with
a merge hook instead of on a push with post update hook.

Extends utils.py so it is callable from the hook and exposes
an utility to set the patch status by patch hash
---
 apps/patchwork/utils.py | 52 +++++++++++++++++++++++++++++++++-
 tools/post-merge.hook   | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 126 insertions(+), 1 deletion(-)
 create mode 100755 tools/post-merge.hook

diff --git a/apps/patchwork/utils.py b/apps/patchwork/utils.py
index 1771167..3b48613 100644
--- a/apps/patchwork/utils.py
+++ b/apps/patchwork/utils.py
@@ -29,7 +29,7 @@  from django.db.models import Max
 from django.db.utils import IntegrityError
 from patchwork.forms import MultiplePatchForm
 from patchwork.models import Bundle, Project, BundlePatch, UserProfile, \
-        PatchChangeNotification, EmailOptout
+        PatchChangeNotification, EmailOptout, Patch, State
 
 def get_patch_ids(d, prefix = 'patch_id'):
     ids = []
@@ -206,3 +206,53 @@  def send_notifications():
         delete_notifications()
 
     return errors
+
+def patch_set_state(patch_hash, state_name):
+    """Update patch state: Inputs are patch hash and state name"""
+    try:
+        patch = Patch.objects.get(hash = patch_hash)
+        patch.state = State.objects.get(name = state_name)
+        patch.save()
+        return True
+    except:	 
+        raise
+
+def main(args):
+    from optparse import OptionParser
+
+    usage = "usage: %prog [options] command"
+    parser = OptionParser(usage=usage)
+    parser.add_option('-#', '--hash',
+                      dest = 'patch_hash', help = 'Patch Hash')
+    parser.add_option('-s', '--state',
+                      dest = 'state_name', help = 'State Name')
+
+    (options, args) = parser.parse_args()
+
+    if len(args) != 1:
+        parser.print_help()
+        sys.exit(-1)
+
+    if args[0] == "set":
+        if not options.patch_hash:
+            print "Missing Patch Hash\n"
+            parser.print_help()
+            sys.exit(-1)
+
+        if not options.state_name:
+            print "Missing State Name\n"
+            parser.print_help()
+            sys.exit(-1)
+
+        try:
+            patch_set_state(options.patch_hash, options.state_name)
+        except:
+            print "E: Failed to update patch!\n"
+
+    else:
+        parser.print_help()
+        sys.exit(-1)
+
+if __name__ == '__main__':
+    import sys
+    sys.exit(main(sys.argv))
diff --git a/tools/post-merge.hook b/tools/post-merge.hook
new file mode 100755
index 0000000..7cba308
--- /dev/null
+++ b/tools/post-merge.hook
@@ -0,0 +1,75 @@ 
+#!/bin/bash
+#
+# Git post-merge hook to update Patchwork patches after Git pulls
+#
+# Copyright © 203 Simo Sorce <simo@samba.org>
+#
+# Based on code from the post-receive hoof from:
+# Copyright © 2010 martin f. krafft <madduck@madduck.net>
+# Released under the GNU General Public License v2 or later.
+set -eu
+
+STATE_MAP="refs/heads/master:Accepted"
+PWDIR=/home/patchwork/patchwork/apps
+
+BASE_DIR=$(git rev-parse --show-toplevel)
+STATE_DIR=${BASE_DIR}/.git/patchwork
+
+do_exit=0
+trap "do_exit=1" INT
+
+get_patchwork_hash()
+{
+  local hash
+  hash=$(git show $1 | python $PWDIR/patchwork/parser.py --hash)
+  echo $hash
+  test -n "$hash"
+}
+
+set_patch_state()
+{
+    PYTHONPATH=${PWDIR} DJANGO_SETTINGS_MODULE=settings python ${PWDIR}/patchwork/utils.py -# ${1} -s ${2} set
+}
+
+update_patches()
+{
+  local cnt; cnt=0
+  for rev in $(git rev-list --no-merges --reverse ${1}..${2}); do
+    if [ "$do_exit" = 1 ]; then
+      echo "I: exiting..." >&2
+      break
+    fi
+    hash=$(get_patchwork_hash $rev) \
+      || { echo "E: failed to hash rev $rev." >&2; continue; }
+    reason="$(set_patch_state $hash $3)" \
+      || { echo "E: failed to update patch ${reason:+: $reason}." >&2; continue; }
+    echo "I: patch $hash updated using rev $rev." >&2
+    cnt=$(($cnt + 1))
+  done
+  echo "I: $cnt patch(es) updated to state $3." >&2
+}
+
+if [ ! -d ${STATE_DIR} ]; then
+    mkdir -p ${STATE_DIR}
+fi
+
+CUR_REFS=$(git show-ref --heads |cut -d ' ' -f 2)
+
+for refname in $CUR_REFS; do
+    BRANCH=$(echo ${refname} | cut -d '/' -f 3)
+    newrev=$(git rev-parse ${refname})
+    if [ ! -f ${STATE_DIR}/${BRANCH} ]; then
+        echo ${newrev} > ${STATE_DIR}/${BRANCH}
+        continue
+    fi
+    oldrev=$(cat ${STATE_DIR}/${BRANCH})
+    echo ${newrev} > ${STATE_DIR}/${BRANCH}
+
+    for i in $STATE_MAP; do
+        key="${i%:*}"
+        if [ "${key}" = "${refname}" ]; then
+            update_patches ${oldrev} ${newrev} ${i#*:}
+            break
+        fi
+    done
+done
-- 
1.7.12.1