changeset 2544:a64887289931

plugin merge-requests, mercurial merge-requests: merge request import implementation
author Goffi <goffi@goffi.org>
date Fri, 30 Mar 2018 17:53:11 +0200
parents 60758de1c227
children 2df1ca79cb30
files src/plugins/plugin_merge_req_mercurial.py src/plugins/plugin_misc_merge_requests.py
diffstat 2 files changed, 76 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/plugins/plugin_merge_req_mercurial.py	Fri Mar 30 17:51:32 2018 +0200
+++ b/src/plugins/plugin_merge_req_mercurial.py	Fri Mar 30 17:53:11 2018 +0200
@@ -44,10 +44,20 @@
     """handle hg commands"""
     hg = None
 
-    def __init__(self, deferred):
+    def __init__(self, deferred, stdin=None):
+        """
+        @param deferred(defer.Deferred): will be called when command is completed
+        @param stdin(str, None): if not None, will be push to standard input
+        """
+        self._stdin = stdin
         self._deferred = deferred
         self.data = []
 
+    def connectionMade(self):
+        if self._stdin is not None:
+            self.transport.write(self._stdin)
+            self.transport.closeStdin()
+
     def outReceived(self, data):
         self.data.append(data)
 
@@ -60,22 +70,31 @@
             log.debug(_('Mercurial command succeed'))
             self._deferred.callback(data)
         else:
-            log.error(_(u"Can't complete Mercurial command (error code: {code}): {message}").format(
+            msg = _(u"Can't complete Mercurial command (error code: {code}): {message}").format(
                 code = reason.value.exitCode,
-                message = data))
-            self._deferred.errback(Failure(RuntimeError))
+                message = data)
+            log.warning(msg)
+            self._deferred.errback(Failure(RuntimeError(msg)))
 
     @classmethod
-    def run(cls, path, command, *args):
+    def run(cls, path, command, *args, **kwargs):
         """Create a new MercurialRegisterProtocol and execute the given mercurialctl command.
 
         @param path(unicode): path to the repository
         @param command(unicode): command to run
         @param *args(unicode): command arguments
+        @param **kwargs: used because Python2 doesn't handle normal kw args after *args
+            can only be:
+            - stdin(unicode, None): data to push to standard input
         @return ((D)):
         """
+        stdin = kwargs.pop('stdin', None)
+        if kwargs:
+            raise exceptions.InternalError(u'only stdin is allowed as keyword argument')
+        if stdin is not None:
+            stdin = stdin.encode('utf-8')
         d = defer.Deferred()
-        mercurial_prot = MercurialProtocol(d)
+        mercurial_prot = MercurialProtocol(d, stdin=stdin)
         cmd_args = [cls.hg, command.encode('utf-8')]
         cmd_args.extend([a.encode('utf-8') for a in args])
         reactor.spawnProcess(mercurial_prot,
@@ -86,6 +105,7 @@
 
 
 class MercurialHandler(object):
+    data_types = (u'mercurial_changeset',)
 
     def __init__(self, host):
         log.info(_(u"Mercurial merge request handler initialization"))
@@ -95,7 +115,7 @@
             raise exceptions.NotFound(_(u"Mercurial executable (hg) not found, can't use Mercurial handler"))
         self.host = host
         self._m = host.plugins['MERGE_REQUESTS']
-        self._m.register('mercurial', self, [u'mercurial_changeset'], SHORT_DESC)
+        self._m.register('mercurial', self, self.data_types, SHORT_DESC)
 
     def check(self, repository):
         d = MercurialProtocol.run(repository, 'identify')
@@ -106,6 +126,16 @@
     def export(self, repository):
         return MercurialProtocol.run(repository, 'export', '-g', '-r', 'outgoing()', '--encoding=utf-8')
 
+    def import_(self, repository, data, data_type, item_id, service, node, extra):
+        parsed_data = self.parse(data)
+        try:
+            parsed_name = parsed_data[0][u'commit_msg'].split(u'\n')[0]
+            parsed_name = parsed_name.replace(u' ', u'_')[:20]
+        except Exception:
+            parsed_name = u''
+        name = u'mr_{item_id}_{parsed_name}'.format(item_id=item_id, parsed_name=parsed_name)
+        return MercurialProtocol.run(repository, 'qimport', '-g', '--name', name, '--encoding=utf-8', '-', stdin=data)
+
     def parse(self, data, data_type=None):
         lines = data.splitlines()
         total_lines = len(lines)
--- a/src/plugins/plugin_misc_merge_requests.py	Fri Mar 30 17:51:32 2018 +0200
+++ b/src/plugins/plugin_misc_merge_requests.py	Fri Mar 30 17:53:11 2018 +0200
@@ -21,6 +21,7 @@
 from sat.core.constants import Const as C
 from sat.core import exceptions
 from twisted.internet import defer
+from twisted.words.protocols.jabber import jid
 from collections import namedtuple
 from sat.tools import utils
 from sat.core.log import getLogger
@@ -89,6 +90,11 @@
                               in_sign='ss', out_sign='aa{ss}',
                               method=self._parseData,
                               async=True)
+        host.bridge.addMethod("mergeRequestsImport", ".plugin",
+                              in_sign='ssssa{ss}s', out_sign='',
+                              method=self._import,
+                              async=True
+                              )
 
     def register(self, name, handler, data_types, short_desc, priority=0):
         """register an merge request handler
@@ -251,3 +257,36 @@
         except KeyError:
             raise exceptions.NotFound(_(u'No handler can handle data type "{type}"').format(type=data_type))
         return defer.maybeDeferred(handler.handler.parse, data, data_type)
+
+    def _import(self, repository, item_id, service=None, node=None, extra=None, profile_key=C.PROF_KEY_NONE):
+        client = self.host.getClient(profile_key)
+        service = jid.JID(service) if service else None
+        d = self.import_request(client, repository, item_id, service, node or None, extra=extra or None)
+        return d
+
+    @defer.inlineCallbacks
+    def import_request(self, client, repository, item, service=None, node=None, extra=None):
+        """Import a merge request in specified directory
+
+        @param repository(unicode): path to the repository where the code stands
+        """
+        if not node:
+            node = NS_MERGE_REQUESTS
+        tickets_xmlui, metadata = yield self._s.getDataFormItems(
+            client,
+            service,
+            node,
+            max_items=1,
+            item_ids=[item],
+            form_ns=NS_MERGE_REQUESTS)
+        ticket_xmlui = tickets_xmlui[0]
+        data = ticket_xmlui.named_widgets[FIELD_DATA].value
+        data_type = ticket_xmlui.named_widgets[FIELD_DATA_TYPE].value
+        try:
+            handler = self._type_handlers[data_type]
+        except KeyError:
+            raise exceptions.NotFound(_(u'No handler found to import {data_type}').format(data_type=data_type))
+        log.info(_(u"Importing patch [{item_id}] using {name} handler").format(
+            item_id = item,
+            name = handler.name))
+        yield handler.handler.import_(repository, data, data_type, item, service, node, extra)