]> source.dussan.org Git - sonarqube.git/commitdiff
Do not execute transition if not available
authorJulien Lancelot <julien.lancelot@gmail.com>
Thu, 18 Jul 2013 07:46:19 +0000 (09:46 +0200)
committerJulien Lancelot <julien.lancelot@gmail.com>
Thu, 18 Jul 2013 07:46:19 +0000 (09:46 +0200)
sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java
sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java
sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceTest.java
sonar-server/src/test/java/org/sonar/server/issue/TransitionActionTest.java

index ec0558f85a82299efa7478ab8c41eab6a7117df9..7793ad6630d1563786d687f3218abcab1a521565 100644 (file)
@@ -72,8 +72,9 @@ public class IssueBulkChangeService {
       if (action == null) {
         throw new BadRequestException("The action : '"+ actionName + "' is unknown");
       }
-      action.verify(issueBulkChangeQuery.properties(actionName), issues, userSession);
-      bulkActions.add(action);
+      if (action.verify(issueBulkChangeQuery.properties(actionName), issues, userSession)) {
+        bulkActions.add(action);
+      }
     }
 
     IssueChangeContext issueChangeContext = IssueChangeContext.createUser(new Date(), userSession.login());
index 16da057468a839c397bf6f7923988261a0953ea5..57e8498e05cdf747c15f5c149a6207cc659812ee 100644 (file)
 
 package org.sonar.server.issue;
 
+import com.google.common.base.Predicate;
 import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.internal.DefaultIssue;
 import org.sonar.core.issue.workflow.IssueWorkflow;
+import org.sonar.core.issue.workflow.Transition;
 import org.sonar.server.user.UserSession;
 
 import java.util.List;
@@ -49,7 +52,21 @@ public class TransitionAction extends Action implements ServerComponent {
 
   @Override
   public boolean execute(Map<String, Object> properties, Context context) {
-    return workflow.doTransition((DefaultIssue) context.issue(), transition(properties), context.issueChangeContext());
+    DefaultIssue issue = (DefaultIssue) context.issue();
+    String transition = transition(properties);
+    if (canExecuteTransition(issue, transition)){
+      return workflow.doTransition((DefaultIssue) context.issue(), transition(properties), context.issueChangeContext());
+    }
+    return false;
+  }
+
+  private boolean canExecuteTransition(Issue issue, final String transition){
+    return Iterables.find(workflow.outTransitions(issue), new Predicate<Transition>() {
+      @Override
+      public boolean apply(Transition input) {
+        return input.key().equals(transition);
+      }
+    }, null) != null;
   }
 
   private String transition(Map<String, Object> properties) {
index bf81543a54b50963407c7d822f43c6a5e70464ae..4ebb6c998c3964046925df72da8b245ebea8a43f 100644 (file)
@@ -177,6 +177,7 @@ public class IssueBulkChangeServiceTest {
     actions.add(action);
     when(action.key()).thenReturn("assign");
     when(action.supports(any(Issue.class))).thenReturn(true);
+    when(action.verify(anyMap(), anyListOf(Issue.class), any(UserSession.class))).thenReturn(true);
     doThrow(new RuntimeException("Error")).when(action).execute(anyMap(), any(IssueBulkChangeService.ActionContext.class));
 
     IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties);
index 6ff1a129c414f7eb91b59b0cb2934040453442fc..b2b6beab89299e5c65237e926a3ba816c3b2ef11 100644 (file)
@@ -27,10 +27,12 @@ import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.internal.DefaultIssue;
 import org.sonar.api.issue.internal.IssueChangeContext;
 import org.sonar.core.issue.workflow.IssueWorkflow;
+import org.sonar.core.issue.workflow.Transition;
 import org.sonar.server.user.MockUserSession;
 
 import java.util.Map;
 
+import static com.google.common.collect.Lists.newArrayList;
 import static com.google.common.collect.Maps.newHashMap;
 import static org.fest.assertions.Assertions.assertThat;
 import static org.fest.assertions.Fail.fail;
@@ -59,10 +61,29 @@ public class TransitionActionTest {
     Action.Context context = mock(Action.Context.class);
     when(context.issue()).thenReturn(issue);
 
+    when(workflow.outTransitions(context.issue())).thenReturn(newArrayList(Transition.create(transition, "REOPEN", "CONFIRMED")));
+
     action.execute(properties, context);
     verify(workflow).doTransition(eq(issue), eq(transition), any(IssueChangeContext.class));
   }
 
+  @Test
+  public void should_not_execute_if_transition_is_not_available() {
+    String transition = "reopen";
+    Map<String, Object> properties = newHashMap();
+    properties.put("transition", transition);
+    DefaultIssue issue = mock(DefaultIssue.class);
+
+    Action.Context context = mock(Action.Context.class);
+    when(context.issue()).thenReturn(issue);
+
+    // Do not contain reopen, transition is not possible
+    when(workflow.outTransitions(context.issue())).thenReturn(newArrayList(Transition.create("resolve", "OPEN", "RESOLVED")));
+
+    assertThat(action.execute(properties, context)).isFalse();
+    verify(workflow, never()).doTransition(eq(issue), eq(transition), any(IssueChangeContext.class));
+  }
+
   @Test
   public void should_verify_fail_if_parameter_not_found() {
     String transition = "reopen";