You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by je...@apache.org on 2015/04/21 11:33:35 UTC

[08/14] allura git commit: [#7866] ticket:754 Refactor code to support can_merge backgroud task (WIP)

[#7866] ticket:754 Refactor code to support can_merge backgroud task (WIP)


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/76f05fab
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/76f05fab
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/76f05fab

Branch: refs/heads/ib/7866
Commit: 76f05fabc43acab1f15416b3dd2423daf34a954b
Parents: fb7f2cf
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri Apr 17 13:04:14 2015 +0000
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Tue Apr 21 08:15:31 2015 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/repository.py         |   8 +-
 Allura/allura/model/repository.py               |  34 ++++--
 Allura/allura/tasks/repo_tasks.py               |   9 +-
 Allura/allura/templates/repo/merge_request.html | 113 +++++++++++++------
 4 files changed, 118 insertions(+), 46 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/76f05fab/Allura/allura/controllers/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index b36449c..07a522b 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -366,7 +366,9 @@ class MergeRequestController(object):
         return dict(
             downstream_app=downstream_app,
             req=self.req,
-            status=self.req.merge_task_status(),
+            can_merge=self.req.can_merge(),
+            can_merge_status=self.req.can_merge_task_status(),
+            merge_status=self.req.merge_task_status(),
             page=page,
             limit=limit,
             count=self.req.discussion_thread.post_count)
@@ -454,6 +456,10 @@ class MergeRequestController(object):
     def merge_task_status(self):
         return {'status': self.req.merge_task_status()}
 
+    @expose('json:')
+    def can_merge_task_status(self):
+        return {'status': self.req.can_merge_task_status()}
+
 
 class RefsController(object):
 

http://git-wip-us.apache.org/repos/asf/allura/blob/76f05fab/Allura/allura/model/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/repository.py b/Allura/allura/model/repository.py
index 8083e17..35d2870 100644
--- a/Allura/allura/model/repository.py
+++ b/Allura/allura/model/repository.py
@@ -838,20 +838,23 @@ class MergeRequest(VersionedArtifact, ActivityObject):
             return False
         return True
 
+    def can_merge_cache(self, source_hash, target_hash):
+        """
+        Returns True/False or None in case of cache miss.
+        """
+        return None
+
     def can_merge(self):
         """
         Returns true if you can merge cleanly (no conflicts)
         """
-        if not self.app.forkable:
-            return False
-        try:
-            result = self.app.repo.can_merge(self)
-        except:
-            log.exception(
-                "Can't determine if merge request %s can be merged",
-                self.url())
-            return False
-        return result
+        cached = self.can_merge_cache(None, None)
+        if cached is not None:
+            return cached
+        in_progress = self.can_merge_task_status() in ['ready', 'busy']
+        if self.app.forkable and not in_progress:
+            from allura.tasks import repo_tasks
+            repo_tasks.can_merge.post(self._id)
 
     def merge(self):
         in_progress = self.merge_task_status() in ['ready', 'busy']
@@ -870,6 +873,17 @@ class MergeRequest(VersionedArtifact, ActivityObject):
             return task.state
         return None
 
+    def can_merge_task_status(self):
+        task = MonQTask.query.find({
+            'state': {'$in': ['busy', 'complete', 'error', 'ready']},  # needed to use index
+            'task_name': 'allura.tasks.repo_tasks.can_merge',
+            'args': [self._id],
+            'time_queue': {'$gt': datetime.utcnow() - timedelta(days=1)}, # constrain on index further
+        }).sort('_id', -1).limit(1).first()
+        if task:
+            return task.state
+        return None
+
 
 # Basic commit information
 # One of these for each commit in the physical repo on disk. The _id is the

http://git-wip-us.apache.org/repos/asf/allura/blob/76f05fab/Allura/allura/tasks/repo_tasks.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tasks/repo_tasks.py b/Allura/allura/tasks/repo_tasks.py
index e873694..d16755c 100644
--- a/Allura/allura/tasks/repo_tasks.py
+++ b/Allura/allura/tasks/repo_tasks.py
@@ -158,8 +158,15 @@ def tarball(revision, path):
 @task
 def merge(merge_request_id):
     from allura import model as M
-    log = logging.getLogger(__name__)
     mr = M.MergeRequest.query.get(_id=merge_request_id)
     mr.app.repo.merge(mr)
     mr.status = 'merged'
     session(mr).flush(mr)
+
+
+@task
+def can_merge(merge_request_id):
+    from allura import model as M
+    mr = M.MergeRequest.query.get(_id=merge_request_id)
+    result = self.app.repo.can_merge(self)
+    # TODO: set cache

http://git-wip-us.apache.org/repos/asf/allura/blob/76f05fab/Allura/allura/templates/repo/merge_request.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/repo/merge_request.html b/Allura/allura/templates/repo/merge_request.html
index 928a0db..99bcdec 100644
--- a/Allura/allura/templates/repo/merge_request.html
+++ b/Allura/allura/templates/repo/merge_request.html
@@ -34,8 +34,8 @@ Merge Request #{{req.request_number}}: {{req.summary}} ({{req.status}})
 
 {% block content %}
   <div class="grid-19">
-    <div id="task_status">
-      {% if status == 'complete' %}
+    <div id="merge_task_status" class="task_status">
+      {% if merge_status == 'complete' %}
         <h2 class="complete">Merged</h2>
       {% else %}
         <img src="{{g.forge_static('images/spinner.gif')}}" class="spinner" style="display:none"/>
@@ -44,6 +44,13 @@ Merge Request #{{req.request_number}}: {{req.summary}} ({{req.status}})
         <h2 class="fail">Something went wrong. Please, merge manually</h2>
       {% endif %}
     </div>
+    <div id="can_merge_task_status" class="task_status">
+      {% if can_merge_status != 'complete' %}
+        <img src="{{g.forge_static('images/spinner.gif')}}" class="spinner" style="display:none"/>
+        <h2 class="busy ready">Checking if merge is possible...</h2>
+        <h2 class="fail">Something went wrong. Please, merge manually</h2>
+      {% endif %}
+    </div>
   </div>
 
   {% if req.downstream_repo %}
@@ -58,20 +65,19 @@ Merge Request #{{req.request_number}}: {{req.summary}} ({{req.status}})
     <div>{{g.markdown.convert(req.description)}}</div>
 
     {% if req.merge_allowed(c.user) %}
-      {% set can_merge = req.can_merge() %}
       <div class="grid-19">
         <form action="merge" method="POST">
           {{ lib.csrf_token() }}
-          <input type="submit" value="Merge"{% if not can_merge or status in ('ready', 'busy') %}disabled="disabled"{% endif %}>
-          {% if can_merge %}
-            <div class="merge-ok">
-              Merge request has no conflicts. You can merge automatically.
-            </div>
-          {% else %}
-            <div class="merge-conflicts">
-              Merge request has conflicts. Follow manual instructions below to merge.
-            </div>
-          {% endif %}
+          <input id="merge-btn" type="submit" value="Merge"{% if not can_merge or merge_status in ('ready', 'busy') %}disabled="disabled"{% endif %}>
+          <div class="merge-help-text can-merge-in-progress" {% if can_merge == None %}style="display: block;"{% endif %}>
+            Checking if merge is possible...
+          </div>
+          <div class="merge-help-text merge-ok" {% if can_merge == True %}style="display: block;"{% endif %}>
+            Merge request has no conflicts. You can merge automatically.
+          </div>
+          <div class="merge-help-text merge-conflicts" {% if can_merge == False %}style="display: block;"{% endif %}>
+            Merge request has conflicts. Follow manual instructions below to merge.
+          </div>
         </form>
       </div>
     {% endif %}
@@ -87,7 +93,7 @@ Merge Request #{{req.request_number}}: {{req.summary}} ({{req.status}})
       <div class="grid-19">
         <textarea style="width:80%; height:60px;" readonly>{{ c.app.repo.merge_command(req) | safe }}</textarea>
       </div>
-      {% if status not in ('ready', 'busy') %}
+      {% if merge_status not in ('ready', 'busy') %}
         {{ c.mr_dispose_form.display(action="save", value=dict(status=req.status)) }}
         <br style="clear:both">
       {% endif %}
@@ -122,15 +128,17 @@ Merge Request #{{req.request_number}}: {{req.summary}} ({{req.status}})
 
 {% block extra_css %}
 <style type="text/css">
+  .merge-help-text { display: none; }
   .merge-ok { color: green; }
   .merge-conflicts { color: red; }
-
-  #task_status { margin: 0 10px; }
-  #task_status h2 { display: none; }
-  #task_status .{{ status }} { display: inline-block; }
-  #task_status h2.complete { color: #C6D880; }
-  #task_status h2.busy, #task_status h2.busy { color: #003565; }
-  #task_status h2.fail { color: #f33; }
+  .can-merge-in-progress { color: grey; }
+
+  .task_status { margin: 0 10px; }
+  .task_status h2 { display: none; }
+  .task_status .{{ merge_status }} { display: inline-block; }
+  .task_status h2.complete { color: #C6D880; }
+  .task_status h2.busy, .task_status h2.busy { color: #003565; }
+  .task_status h2.fail { color: #f33; }
 </style>
 {% endblock %}
 
@@ -138,35 +146,72 @@ Merge Request #{{req.request_number}}: {{req.summary}} ({{req.status}})
 {{ super() }}
 <script type="text/javascript">
 $(function() {
-    {% if status in ('ready', 'busy') %}
-        $('.spinner').show();
+    {% if merge_status in ('ready', 'busy') %}
+        $('#merge_task_status > .spinner').show();
         var delay = 500;
-        function check_status() {
+        function check_merge_status() {
           $.get("{{request.path.rstrip('/') + '/merge_task_status'}}", function(data) {
                 if (data.status === 'complete') {
-                    $('.spinner').hide();
-                    $('#task_status h2').hide();
-                    $('#task_status h2.complete').show();
+                    $('#merge_task_status > .spinner').hide();
+                    $('#merge_task_status h2').hide();
+                    $('#merge_task_status h2.complete').show();
                     location.reload();
                 } else {
                     if (data.status === 'ready' || data.status === 'busy') {
                         // keep waiting
-                        $('#task_status h2').hide();
-                        $('#task_status h2.busy').show();
+                        $('#merge_task_status h2').hide();
+                        $('#merge_task_status h2.busy').show();
+                    } else {
+                        // something went wrong
+                        $('#merge_task_status > .spinner').hide();
+                        $('#merge_task_status h2').hide();
+                        $('#merge_task_status h2.fail').show();
+                    }
+                    if (delay < 60000){
+                        delay = delay * 2;
+                    }
+                    window.setTimeout(check_merge_status, delay);
+                }
+            });
+        }
+        window.setTimeout(check_merge_status, delay);
+    {% endif %}
+
+    {% if can_merge_status in ('ready', 'busy') %}
+        $('#can_merge_task_status > .spinner').show();
+        var delay = 500;
+        function check_can_merge_status() {
+          $.get("{{request.path.rstrip('/') + '/can_merge_task_status'}}", function(data) {
+                if (data.status === 'complete') {
+                    $('#can_merge_task_status > .spinner').hide();
+                    $('#can_merge_task_status h2').hide();
+                    // TODO: check if actually can merge and show appropriate message
+                    $('.merge-help-text').hide();
+                    $('.merge-ok').show();
+                    $('.merge-btn').prop('disabled', false);
+                } else {
+                    if (data.status === 'ready' || data.status === 'busy') {
+                        // keep waiting
+                        $('#can_merge_task_status h2').hide();
+                        $('#can_merge_task_status h2.busy').show();
+                        $('.merge-help-text').hide();
+                        $('.can-merge-in-progress').show();
                     } else {
                         // something went wrong
-                        $('.spinner').hide();
-                        $('#task_status h2').hide();
-                        $('#task_status h2.fail').show();
+                        $('#can_merge_task_status > .spinner').hide();
+                        $('#can_merge_task_status h2').hide();
+                        $('#merge_task_status h2.fail').show();
+                        $('.merge-help-text').hide();
+                        $('.merge-conflicts').show();
                     }
                     if (delay < 60000){
                         delay = delay * 2;
                     }
-                    window.setTimeout(check_status, delay);
+                    window.setTimeout(check_can_merge_status, delay);
                 }
             });
         }
-        window.setTimeout(check_status, delay);
+        window.setTimeout(check_can_merge_status, delay);
     {% endif %}
 });
 </script>