]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6012 Create WS /batch/issues
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 19 Jan 2015 15:57:17 +0000 (16:57 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 19 Jan 2015 16:01:44 +0000 (17:01 +0100)
31 files changed:
server/sonar-server/src/main/java/org/sonar/server/batch/BatchWs.java
server/sonar-server/src/main/java/org/sonar/server/batch/GlobalRepositoryAction.java
server/sonar-server/src/main/java/org/sonar/server/batch/IssuesAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java
server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueDao.java
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueDoc.java
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/test/java/org/sonar/server/batch/BatchWsTest.java
server/sonar-server/src/test/java/org/sonar/server/batch/GlobalRepositoryActionTest.java
server/sonar-server/src/test/java/org/sonar/server/batch/IssuesActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/batch/ProjectRepositoryActionTest.java
server/sonar-server/src/test/java/org/sonar/server/batch/ProjectRepositoryLoaderMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/es/EsTester.java
server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueDaoTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/InternalPermissionTemplateServiceTest.java
server/sonar-server/src/test/resources/org/sonar/server/batch/IssuesActionTest/issues_on_module-expected.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/batch/IssuesActionTest/issues_on_project-expected.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/batch/IssuesActionTest/shared.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/select_non_closed_issues_by_module_uuid.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/select_non_closed_issues_by_project_uuid.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/shared.xml
sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/issues/PreviousIssueHelper.java
sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/input/issues/PreviousIssueHelperTest.java
sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java
sonar-core/src/main/java/org/sonar/core/issue/db/BatchIssueDto.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/permission/GlobalPermissions.java
sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml
sonar-core/src/test/java/org/sonar/core/user/RoleDaoTest.java

index defb80f84d1e1d2a7d8b00a8c2c82255de6a719f..fdddd299e55dcb980f919fbb13548dae2b15b0cd 100644 (file)
@@ -35,11 +35,13 @@ public class BatchWs implements WebService {
   private final BatchIndex batchIndex;
   private final GlobalRepositoryAction globalRepositoryAction;
   private final ProjectRepositoryAction projectRepositoryAction;
+  private final IssuesAction issuesAction;
 
-  public BatchWs(BatchIndex batchIndex, GlobalRepositoryAction globalRepositoryAction, ProjectRepositoryAction projectRepositoryAction) {
+  public BatchWs(BatchIndex batchIndex, GlobalRepositoryAction globalRepositoryAction, ProjectRepositoryAction projectRepositoryAction, IssuesAction issuesAction) {
     this.batchIndex = batchIndex;
     this.globalRepositoryAction = globalRepositoryAction;
     this.projectRepositoryAction = projectRepositoryAction;
+    this.issuesAction = issuesAction;
   }
 
   @Override
@@ -52,6 +54,7 @@ public class BatchWs implements WebService {
     defineFileAction(controller);
     globalRepositoryAction.define(controller);
     projectRepositoryAction.define(controller);
+    issuesAction.define(controller);
 
     controller.done();
   }
index 59451e4c2a0f90de8795956923b84ea899f9a68d..b939ac22566437f39761d389a06b62483627e57e 100644 (file)
@@ -58,7 +58,7 @@ public class GlobalRepositoryAction implements RequestHandler {
   public void handle(Request request, Response response) throws Exception {
     UserSession userSession = UserSession.get();
     boolean hasScanPerm = userSession.hasGlobalPermission(GlobalPermissions.SCAN_EXECUTION);
-    boolean hasDryRunPerm = userSession.hasGlobalPermission(GlobalPermissions.DRY_RUN_EXECUTION);
+    boolean hasDryRunPerm = userSession.hasGlobalPermission(GlobalPermissions.PREVIEW_EXECUTION);
 
     DbSession session = dbClient.openSession(false);
     try {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/batch/IssuesAction.java b/server/sonar-server/src/main/java/org/sonar/server/batch/IssuesAction.java
new file mode 100644 (file)
index 0000000..cc4cfcc
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.batch;
+
+import com.google.common.base.Charsets;
+import org.apache.ibatis.session.ResultContext;
+import org.apache.ibatis.session.ResultHandler;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.RequestHandler;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.web.UserRole;
+import org.sonar.batch.protocol.input.issues.PreviousIssue;
+import org.sonar.batch.protocol.input.issues.PreviousIssueHelper;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.db.BatchIssueDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.plugins.MimeTypes;
+import org.sonar.server.user.UserSession;
+
+import javax.annotation.Nullable;
+
+import java.io.OutputStreamWriter;
+
+public class IssuesAction implements RequestHandler {
+
+  private static final String PARAM_KEY = "key";
+
+  private final DbClient dbClient;
+
+  public IssuesAction(DbClient dbClient) {
+    this.dbClient = dbClient;
+  }
+
+  void define(WebService.NewController controller) {
+    WebService.NewAction action = controller.createAction("issues")
+      .setDescription("Return open issues")
+      .setSince("5.1")
+      .setInternal(true)
+      .setHandler(this);
+
+    action
+      .createParam(PARAM_KEY)
+      .setRequired(true)
+      .setDescription("Project or module key")
+      .setExampleValue("org.codehaus.sonar:sonar");
+  }
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    UserSession.get().checkGlobalPermission(GlobalPermissions.PREVIEW_EXECUTION);
+    final String moduleKey = request.mandatoryParam(PARAM_KEY);
+
+    PreviousIssueHelper previousIssueHelper = PreviousIssueHelper.create(new OutputStreamWriter(response.stream().output(), Charsets.UTF_8));
+    DbSession session = dbClient.openSession(false);
+    try {
+      ComponentDto moduleOrProject = dbClient.componentDao().getByKey(session, moduleKey);
+      UserSession.get().checkComponentPermission(UserRole.USER, moduleKey);
+
+      response.stream().setMediaType(MimeTypes.JSON);
+      BatchIssueResultHandler batchIssueResultHandler = new BatchIssueResultHandler(previousIssueHelper);
+      if (moduleOrProject.isRootProject()) {
+        dbClient.issueDao().selectNonClosedIssuesByProjectUuid(session, moduleOrProject.uuid(), batchIssueResultHandler);
+      } else {
+        dbClient.issueDao().selectNonClosedIssuesByModuleUuid(session, moduleOrProject.uuid(), batchIssueResultHandler);
+      }
+
+    } finally {
+      previousIssueHelper.close();
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  private static class BatchIssueResultHandler implements ResultHandler {
+    private final PreviousIssueHelper previousIssueHelper;
+
+    public BatchIssueResultHandler(PreviousIssueHelper previousIssueHelper) {
+      this.previousIssueHelper = previousIssueHelper;
+    }
+
+    @Override
+    public void handleResult(ResultContext rc) {
+      previousIssueHelper.addIssue((BatchIssueDto) rc.getResultObject(), new BatchIssueFunction());
+    }
+  }
+
+  private static class BatchIssueFunction implements PreviousIssueHelper.Function<BatchIssueDto, PreviousIssue> {
+    @Override
+    public PreviousIssue apply(@Nullable BatchIssueDto batchIssueDto) {
+      if (batchIssueDto != null) {
+        return new PreviousIssue()
+          .setKey(batchIssueDto.getKey())
+          .setComponentPath(batchIssueDto.getComponentPath())
+          .setChecksum(batchIssueDto.getChecksum())
+          .setAssigneeLogin(batchIssueDto.getAssigneeLogin())
+          .setAssigneeFullname(batchIssueDto.getAssigneeName())
+          .setLine(batchIssueDto.getLine())
+          .setRuleKey(batchIssueDto.getRuleRepo(), batchIssueDto.getRuleKey())
+          .setMessage(batchIssueDto.getMessage())
+          .setResolution(batchIssueDto.getResolution())
+          .setStatus(batchIssueDto.getStatus());
+      }
+      return null;
+    }
+  }
+}
index 90c10f94b5a807193ae129608bfed2acea94c71c..61917a481939b1e8e9d511f623c1c13858ec2b35 100644 (file)
@@ -135,7 +135,7 @@ public class ProjectRepositoryLoader implements ServerComponent {
   }
 
   private void addSettingsToChildrenModules(ProjectReferentials ref, String moduleKey, Map<String, String> parentProperties, TreeModuleSettings treeModuleSettings,
-                                            boolean hasScanPerm, DbSession session) {
+    boolean hasScanPerm, DbSession session) {
     Map<String, String> currentParentProperties = newHashMap();
     currentParentProperties.putAll(parentProperties);
     currentParentProperties.putAll(getPropertiesMap(treeModuleSettings.findModuleSettings(moduleKey), hasScanPerm));
@@ -235,7 +235,7 @@ public class ProjectRepositoryLoader implements ServerComponent {
   private void checkPermission(boolean preview) {
     UserSession userSession = UserSession.get();
     boolean hasScanPerm = userSession.hasGlobalPermission(GlobalPermissions.SCAN_EXECUTION);
-    boolean hasPreviewPerm = userSession.hasGlobalPermission(GlobalPermissions.DRY_RUN_EXECUTION);
+    boolean hasPreviewPerm = userSession.hasGlobalPermission(GlobalPermissions.PREVIEW_EXECUTION);
     if (!hasPreviewPerm && !hasScanPerm) {
       throw new ForbiddenException("You're not authorized to execute any SonarQube analysis. Please contact your SonarQube administrator.");
     }
index 0b2aba8a5a8ef5fccd92bfaf49cc7921b765ba60..f8bd5f91d5312cd173386fbf53db5234917c764c 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.issue.db;
 
+import org.apache.ibatis.session.ResultHandler;
 import org.sonar.core.issue.db.IssueDto;
 import org.sonar.core.issue.db.IssueMapper;
 import org.sonar.core.persistence.DaoComponent;
@@ -58,6 +59,14 @@ public class IssueDao extends org.sonar.core.issue.db.IssueDao implements DaoCom
     return mapper(session).selectByKeys(keys);
   }
 
+  public void selectNonClosedIssuesByModuleUuid(DbSession session, String moduleUuid, ResultHandler handler) {
+    session.select("org.sonar.core.issue.db.IssueMapper.selectNonClosedIssuesByModuleUuid", moduleUuid, handler);
+  }
+
+  public void selectNonClosedIssuesByProjectUuid(DbSession session, String projectUuid, ResultHandler handler) {
+    session.select("org.sonar.core.issue.db.IssueMapper.selectNonClosedIssuesByProjectUuid", projectUuid, handler);
+  }
+
   public void insert(DbSession session, IssueDto dto) {
     mapper(session).insert(dto);
   }
index c156bf24d2c36ebc8f2633c61d5df999449bec35..dbda8319ab71aa50f4a8176d04fd65800c502694 100644 (file)
@@ -30,11 +30,7 @@ import org.sonar.server.search.BaseDoc;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 public class IssueDoc extends BaseDoc implements Issue {
 
@@ -199,101 +195,125 @@ public class IssueDoc extends BaseDoc implements Issue {
     return getNullableField(IssueIndexDefinition.FIELD_ISSUE_FILE_PATH);
   }
 
-  public void setKey(@Nullable String s) {
+  public IssueDoc setKey(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_KEY, s);
+    return this;
   }
 
-  public void setComponentUuid(@Nullable String s) {
+  public IssueDoc setComponentUuid(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, s);
+    return this;
   }
 
-  public void setModuleUuid(@Nullable String s) {
+  public IssueDoc setModuleUuid(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, s);
+    return this;
   }
 
-  public void setProjectUuid(@Nullable String s) {
+  public IssueDoc setProjectUuid(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, s);
+    return this;
   }
 
-  public void setRuleKey(@Nullable String s) {
+  public IssueDoc setRuleKey(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_RULE_KEY, s);
+    return this;
   }
 
-  public void setLanguage(@Nullable String s) {
+  public IssueDoc setLanguage(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_LANGUAGE, s);
+    return this;
   }
 
-  public void setSeverity(@Nullable String s) {
+  public IssueDoc setSeverity(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_SEVERITY, s);
     setField(IssueIndexDefinition.FIELD_ISSUE_SEVERITY_VALUE, Severity.ALL.indexOf(s));
+    return this;
   }
 
-  public void setMessage(@Nullable String s) {
+  public IssueDoc setMessage(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_MESSAGE, s);
+    return this;
   }
 
-  public void setLine(@Nullable Integer i) {
+  public IssueDoc setLine(@Nullable Integer i) {
     setField(IssueIndexDefinition.FIELD_ISSUE_LINE, i);
+    return this;
   }
 
-  public void setEffortToFix(@Nullable Double d) {
+  public IssueDoc setEffortToFix(@Nullable Double d) {
     setField(IssueIndexDefinition.FIELD_ISSUE_EFFORT, d);
+    return this;
   }
 
-  public void setStatus(@Nullable String s) {
+  public IssueDoc setStatus(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_STATUS, s);
+    return this;
   }
 
-  public void setResolution(@Nullable String s) {
+  public IssueDoc setResolution(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_RESOLUTION, s);
+    return this;
   }
 
-  public void setReporter(@Nullable String s) {
+  public IssueDoc setReporter(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_REPORTER, s);
+    return this;
   }
 
-  public void setAssignee(@Nullable String s) {
+  public IssueDoc setAssignee(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE, s);
+    return this;
   }
 
-  public void setFuncUpdateDate(@Nullable Date d) {
+  public IssueDoc setFuncUpdateDate(@Nullable Date d) {
     setField(IssueIndexDefinition.FIELD_ISSUE_FUNC_UPDATED_AT, d);
+    return this;
   }
 
-  public void setFuncCreationDate(@Nullable Date d) {
+  public IssueDoc setFuncCreationDate(@Nullable Date d) {
     setField(IssueIndexDefinition.FIELD_ISSUE_FUNC_CREATED_AT, d);
+    return this;
   }
 
-  public void setTechnicalUpdateDate(@Nullable Date d) {
+  public IssueDoc setTechnicalUpdateDate(@Nullable Date d) {
     setField(IssueIndexDefinition.FIELD_ISSUE_TECHNICAL_UPDATED_AT, d);
+    return this;
   }
 
-  public void setFuncCloseDate(@Nullable Date d) {
+  public IssueDoc setFuncCloseDate(@Nullable Date d) {
     setField(IssueIndexDefinition.FIELD_ISSUE_FUNC_CLOSED_AT, d);
+    return this;
   }
 
-  public void setAttributes(@Nullable String s) {
+  public IssueDoc setAttributes(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_ATTRIBUTES, s);
+    return this;
   }
 
-  public void setAuthorLogin(@Nullable String s) {
+  public IssueDoc setAuthorLogin(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_AUTHOR_LOGIN, s);
+    return this;
   }
 
-  public void setActionPlanKey(@Nullable String s) {
+  public IssueDoc setActionPlanKey(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_ACTION_PLAN, s);
+    return this;
   }
 
-  public void setDebt(@Nullable Long l) {
+  public IssueDoc setDebt(@Nullable Long l) {
     setField(IssueIndexDefinition.FIELD_ISSUE_DEBT, l);
+    return this;
   }
 
-  public void setFilePath(@Nullable String s) {
+  public IssueDoc setFilePath(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_FILE_PATH, s);
+    return this;
   }
 
-  public void setModuleUuidPath(@Nullable String s) {
+  public IssueDoc setModuleUuidPath(@Nullable String s) {
     setField(IssueIndexDefinition.FIELD_ISSUE_MODULE_PATH, s);
+    return this;
   }
 
   @Override
@@ -302,7 +322,8 @@ public class IssueDoc extends BaseDoc implements Issue {
     return getNullableField(IssueIndexDefinition.FIELD_ISSUE_TAGS);
   }
 
-  public void setTags(@Nullable Collection<String> tags) {
+  public IssueDoc setTags(@Nullable Collection<String> tags) {
     setField(IssueIndexDefinition.FIELD_ISSUE_TAGS, tags);
+    return this;
   }
 }
index 9d055d022edc5e52c588b3d2b313e63e7b469405..396ad9010be1cd40018ede4190d17468dff2aaa6 100644 (file)
@@ -30,12 +30,7 @@ import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.action.search.SearchType;
 import org.elasticsearch.common.unit.TimeValue;
-import org.elasticsearch.index.query.BoolFilterBuilder;
-import org.elasticsearch.index.query.FilterBuilder;
-import org.elasticsearch.index.query.FilterBuilders;
-import org.elasticsearch.index.query.OrFilterBuilder;
-import org.elasticsearch.index.query.QueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.index.query.*;
 import org.elasticsearch.search.aggregations.AggregationBuilder;
 import org.elasticsearch.search.aggregations.AggregationBuilders;
 import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder;
@@ -49,24 +44,13 @@ import org.sonar.api.rule.Severity;
 import org.sonar.server.es.Sorting;
 import org.sonar.server.issue.IssueQuery;
 import org.sonar.server.issue.filter.IssueFilterParameters;
-import org.sonar.server.search.BaseIndex;
-import org.sonar.server.search.FacetValue;
-import org.sonar.server.search.IndexDefinition;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.search.Result;
-import org.sonar.server.search.SearchClient;
-import org.sonar.server.search.StickyFacetBuilder;
+import org.sonar.server.search.*;
 import org.sonar.server.user.UserSession;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import static com.google.common.collect.Lists.newArrayList;
 
@@ -528,7 +512,7 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
     Terms result = count.addAggregation(aggreg).get().getAggregations().get("_ref");
 
     Map<String, Long> map = Maps.newHashMap();
-    for (Bucket bucket: result.getBuckets()) {
+    for (Bucket bucket : result.getBuckets()) {
       map.put(bucket.getKey(), bucket.getDocCount());
     }
     return map;
index 77457db98cbf54be739d044e50258d8fc8fa39e0..ef987e1575d21b6920f2785698bd1b022ac9be4c 100644 (file)
@@ -352,6 +352,8 @@ class ServerComponents {
     pico.addSingleton(ProjectRepositoryAction.class);
     pico.addSingleton(ProjectRepositoryLoader.class);
     pico.addSingleton(SubmitReportWsAction.class);
+    pico.addSingleton(IssuesSearchService.class);
+    pico.addSingleton(IssuesAction.class);
     pico.addSingleton(BatchWs.class);
 
     // update center
index 58b5fcf6a0dcee81d124e4fcdc66ffabf20a49db..539d2cff045a8c2f9dd5a86c16ee405fdc972d5c 100644 (file)
@@ -57,7 +57,8 @@ public class BatchWsTest {
   public void before() throws IOException {
     tester = new WsTester(new BatchWs(batchIndex,
       new GlobalRepositoryAction(mock(DbClient.class), mock(PropertiesDao.class)),
-      new ProjectRepositoryAction(mock(ProjectRepositoryLoader.class))));
+      new ProjectRepositoryAction(mock(ProjectRepositoryLoader.class)),
+      new IssuesAction(mock(DbClient.class))));
   }
 
   @Test
index 8ec5ca9145e6ef67d12f39f7704875644e8baf3c..fdce8473e1ee94741731fc833a16bd17ba66fa95 100644 (file)
@@ -59,7 +59,7 @@ public class GlobalRepositoryActionTest {
     when(dbClient.openSession(false)).thenReturn(session);
     when(dbClient.metricDao()).thenReturn(metricDao);
 
-    tester = new WsTester(new BatchWs(mock(BatchIndex.class), new GlobalRepositoryAction(dbClient, propertiesDao), mock(ProjectRepositoryAction.class)));
+    tester = new WsTester(new BatchWs(mock(BatchIndex.class), new GlobalRepositoryAction(dbClient, propertiesDao), mock(ProjectRepositoryAction.class), mock(IssuesAction.class)));
   }
 
   @Test
@@ -75,7 +75,7 @@ public class GlobalRepositoryActionTest {
 
   @Test
   public void return_global_settings() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION, GlobalPermissions.DRY_RUN_EXECUTION);
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION, GlobalPermissions.PREVIEW_EXECUTION);
 
     when(propertiesDao.selectGlobalProperties(session)).thenReturn(newArrayList(
       new PropertyDto().setKey("foo").setValue("bar"),
@@ -89,7 +89,7 @@ public class GlobalRepositoryActionTest {
 
   @Test
   public void return_only_license_settings_without_scan_but_with_preview_permission() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.DRY_RUN_EXECUTION);
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.PREVIEW_EXECUTION);
 
     when(propertiesDao.selectGlobalProperties(session)).thenReturn(newArrayList(
       new PropertyDto().setKey("foo").setValue("bar"),
diff --git a/server/sonar-server/src/test/java/org/sonar/server/batch/IssuesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/batch/IssuesActionTest.java
new file mode 100644 (file)
index 0000000..ca142cd
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.batch;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.platform.Server;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.core.properties.PropertiesDao;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.issue.db.IssueDao;
+import org.sonar.server.user.MockUserSession;
+import org.sonar.server.ws.WsTester;
+
+import static org.mockito.Mockito.mock;
+
+public class IssuesActionTest {
+
+  private final static String PROJECT_KEY = "struts";
+  private final static String MODULE_KEY = "struts-core";
+
+  WsTester tester;
+
+  IssuesAction issuesAction;
+
+  @Rule
+  public DbTester db = new DbTester();
+
+  private DbSession session;
+
+  @Before
+  public void before() throws Exception {
+    this.session = db.myBatis().openSession(false);
+
+    DbClient dbClient = new DbClient(db.database(), db.myBatis(), new IssueDao(db.myBatis()), new ComponentDao());
+    issuesAction = new IssuesAction(dbClient);
+
+    tester = new WsTester(new BatchWs(
+      new BatchIndex(mock(Server.class)),
+      new GlobalRepositoryAction(mock(DbClient.class), mock(PropertiesDao.class)),
+      new ProjectRepositoryAction(mock(ProjectRepositoryLoader.class)),
+      issuesAction)
+      );
+  }
+
+  @After
+  public void after() {
+    this.session.close();
+  }
+
+  @Test
+  public void return_issues_on_project() throws Exception {
+    db.prepareDbUnit(getClass(), "shared.xml");
+
+    MockUserSession.set().setLogin("henry").setGlobalPermissions(GlobalPermissions.PREVIEW_EXECUTION).addComponentPermission(UserRole.USER, PROJECT_KEY, PROJECT_KEY);
+
+    WsTester.TestRequest request = tester.newGetRequest("batch", "issues").setParam("key", PROJECT_KEY);
+    request.execute().assertJson(getClass(), "issues_on_project-expected.json");
+  }
+
+  @Test
+  public void return_issues_on_module() throws Exception {
+    db.prepareDbUnit(getClass(), "shared.xml");
+
+    MockUserSession.set().setLogin("henry").setGlobalPermissions(GlobalPermissions.PREVIEW_EXECUTION).addComponentPermission(UserRole.USER, PROJECT_KEY, MODULE_KEY);
+
+    WsTester.TestRequest request = tester.newGetRequest("batch", "issues").setParam("key", MODULE_KEY);
+    request.execute().assertJson(getClass(), "issues_on_module-expected.json");
+  }
+
+  @Test(expected = ForbiddenException.class)
+  public void fail_without_preview_permission() throws Exception {
+    db.prepareDbUnit(getClass(), "shared.xml");
+
+    MockUserSession.set().setLogin("henry").setGlobalPermissions(GlobalPermissions.PROVISIONING).addComponentPermission(UserRole.USER, PROJECT_KEY, MODULE_KEY);
+
+    WsTester.TestRequest request = tester.newGetRequest("batch", "issues").setParam("key", MODULE_KEY);
+    request.execute();
+  }
+
+  @Test(expected = ForbiddenException.class)
+  public void fail_without_user_permission_on_project() throws Exception {
+    db.prepareDbUnit(getClass(), "shared.xml");
+
+    MockUserSession.set().setLogin("henry").setGlobalPermissions(GlobalPermissions.PREVIEW_EXECUTION).addComponentPermission(UserRole.CODEVIEWER, PROJECT_KEY, PROJECT_KEY);
+
+    WsTester.TestRequest request = tester.newGetRequest("batch", "issues").setParam("key", MODULE_KEY);
+    request.execute();
+  }
+
+  @Test(expected = ForbiddenException.class)
+  public void fail_without_user_permission_on_module() throws Exception {
+    db.prepareDbUnit(getClass(), "shared.xml");
+
+    MockUserSession.set().setLogin("henry").setGlobalPermissions(GlobalPermissions.PREVIEW_EXECUTION).addComponentPermission(UserRole.CODEVIEWER, PROJECT_KEY, MODULE_KEY);
+
+    WsTester.TestRequest request = tester.newGetRequest("batch", "issues").setParam("key", MODULE_KEY);
+    request.execute();
+  }
+}
index 53183b4ff5b4a4863768be0478957a5a1c6c8050..4dd4ae8e46f6f2866cdf7ca027e4efba2a146ea5 100644 (file)
@@ -37,14 +37,14 @@ import static org.mockito.Mockito.when;
 public class ProjectRepositoryActionTest {
 
   @Mock
-  ProjectRepositoryLoader projectReferentialsLoader;
+  ProjectRepositoryLoader projectRepositoryLoader;
 
   WsTester tester;
 
   @Before
   public void setUp() throws Exception {
     tester = new WsTester(new BatchWs(mock(BatchIndex.class), mock(GlobalRepositoryAction.class),
-      new ProjectRepositoryAction(projectReferentialsLoader)));
+      new ProjectRepositoryAction(projectRepositoryLoader), mock(IssuesAction.class)));
   }
 
   @Test
@@ -55,7 +55,7 @@ public class ProjectRepositoryActionTest {
     when(projectReferentials.toJson()).thenReturn("{\"settingsByModule\": {}}");
 
     ArgumentCaptor<ProjectRepositoryQuery> queryArgumentCaptor = ArgumentCaptor.forClass(ProjectRepositoryQuery.class);
-    when(projectReferentialsLoader.load(queryArgumentCaptor.capture())).thenReturn(projectReferentials);
+    when(projectRepositoryLoader.load(queryArgumentCaptor.capture())).thenReturn(projectReferentials);
 
     WsTester.TestRequest request = tester.newGetRequest("batch", "project")
       .setParam("key", projectKey)
index 7e5b2f6cd1f02d8bba074ade2c1a7f8052fccd29..bcc53133743f7b1283c49e2fcaa24481f526a26a 100644 (file)
@@ -111,7 +111,7 @@ public class ProjectRepositoryLoaderMediumTest {
 
   @Test
   public void not_returned_secured_settings_with_only_preview_permission() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.DRY_RUN_EXECUTION);
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.PREVIEW_EXECUTION);
 
     ComponentDto project = ComponentTesting.newProjectDto();
     tester.get(DbClient.class).componentDao().insert(dbSession, project);
@@ -659,7 +659,7 @@ public class ProjectRepositoryLoaderMediumTest {
 
   @Test
   public void fail_when_not_preview_and_only_dry_run_permission() throws Exception {
-    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.DRY_RUN_EXECUTION);
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.PREVIEW_EXECUTION);
 
     ComponentDto project = ComponentTesting.newProjectDto();
     tester.get(DbClient.class).componentDao().insert(dbSession, project);
@@ -676,7 +676,7 @@ public class ProjectRepositoryLoaderMediumTest {
   }
 
   @Test
-  public void add_file_data_on_single_project() throws Exception {
+  public void return_file_data_from_single_project() throws Exception {
     MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
 
     ComponentDto project = ComponentTesting.newProjectDto();
@@ -696,7 +696,7 @@ public class ProjectRepositoryLoaderMediumTest {
   }
 
   @Test
-  public void add_file_data_on_multi_modules() throws Exception {
+  public void return_file_data_from_multi_modules() throws Exception {
     MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
 
     ComponentDto project = ComponentTesting.newProjectDto();
@@ -723,6 +723,34 @@ public class ProjectRepositoryLoaderMediumTest {
     assertThat(ref.fileData(module.key(), moduleFile.path()).hash()).isEqualTo("789456");
   }
 
+  @Test
+  public void return_file_data_from_module() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    tester.get(DbClient.class).componentDao().insert(dbSession, project);
+    addDefaultProfile();
+
+    // File on project
+    ComponentDto projectFile = ComponentTesting.newFileDto(project, "projectFile");
+    tester.get(DbClient.class).componentDao().insert(dbSession, projectFile);
+    tester.get(FileSourceDao.class).insert(newFileSourceDto(projectFile).setSrcHash("123456"));
+
+    ComponentDto module = ComponentTesting.newModuleDto(project);
+    tester.get(DbClient.class).componentDao().insert(dbSession, module);
+
+    // File on module
+    ComponentDto moduleFile = ComponentTesting.newFileDto(module, "moduleFile");
+    tester.get(DbClient.class).componentDao().insert(dbSession, moduleFile);
+    tester.get(FileSourceDao.class).insert(newFileSourceDto(moduleFile).setSrcHash("789456"));
+
+    dbSession.commit();
+
+    ProjectReferentials ref = loader.load(ProjectRepositoryQuery.create().setModuleKey(module.key()));
+    assertThat(ref.fileData(module.key(), moduleFile.path()).hash()).isEqualTo("789456");
+    assertThat(ref.fileData(project.key(), projectFile.path())).isNull();
+  }
+
   private void addDefaultProfile() {
     QualityProfileDto profileDto = QProfileTesting.newDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(
       DateUtils.formatDateTime(new Date()));
index 2cc58e8f6a4fb76d03c4cd48508f3f803f1b91e7..1efc1df9d8a09f840d330ac12316fdf7ba583c59 100644 (file)
@@ -48,6 +48,7 @@ import org.sonar.core.profiling.Profiling;
 import org.sonar.server.search.BaseDoc;
 import org.sonar.test.TestUtils;
 
+import java.io.File;
 import java.io.FileInputStream;
 import java.util.Collections;
 import java.util.List;
@@ -147,8 +148,11 @@ public class EsTester extends ExternalResource {
   public void putDocuments(String index, String type, Class<?> testClass, String... jsonPaths) throws Exception {
     BulkRequestBuilder bulk = client.prepareBulk().setRefresh(true);
     for (String path : jsonPaths) {
-      bulk.add(new IndexRequest(index, type).source(IOUtils.toString(
-        new FileInputStream(TestUtils.getResource(testClass, path)))));
+      File file = TestUtils.getResource(testClass, path);
+      if (file == null) {
+        throw new IllegalArgumentException(String.format("File '%s' hasn't been found in folder '%s'", path, testClass.getSimpleName()));
+      }
+      bulk.add(new IndexRequest(index, type).source(IOUtils.toString(new FileInputStream(file))));
     }
     bulk.get();
   }
index a42a1287b296d3f16619465189a1abca04898a32..1a36eab8aa484333e81a3e567e7fe7bef792dafc 100644 (file)
  */
 package org.sonar.server.issue.db;
 
+import org.apache.ibatis.executor.result.DefaultResultHandler;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.sonar.api.issue.Issue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.System2;
 import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.db.BatchIssueDto;
 import org.sonar.core.issue.db.IssueDto;
 import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.persistence.DbSession;
@@ -35,18 +37,15 @@ import java.util.Arrays;
 import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
 
 public class IssueDaoTest extends AbstractDaoTestCase {
 
   private IssueDao dao;
   private DbSession session;
-  private System2 system2;
 
   @Before
   public void before() throws Exception {
     this.session = getMyBatis().openSession(false);
-    this.system2 = mock(System2.class);
     this.dao = new IssueDao(getMyBatis());
   }
 
@@ -134,6 +133,62 @@ public class IssueDaoTest extends AbstractDaoTestCase {
     assertThat(issue.getProjectKey()).isEqualTo("struts");
   }
 
+  @Test
+  public void select_non_closed_issues_by_module_uuid() {
+    setupData("shared", "select_non_closed_issues_by_module_uuid");
+
+    // BCDE is a non-root module, we should find 2 issues from classes and one on itself
+    DefaultResultHandler handler = new DefaultResultHandler();
+    dao.selectNonClosedIssuesByModuleUuid(session, "BCDE", handler);
+    assertThat(handler.getResultList()).extracting("key").containsOnly("100", "101", "103");
+
+    // DBCA is a a simple project with a single file
+    handler = new DefaultResultHandler();
+    dao.selectNonClosedIssuesByModuleUuid(session, "DBCA", handler);
+    assertThat(handler.getResultList()).hasSize(1);
+
+    BatchIssueDto batchIssueDto = (BatchIssueDto) handler.getResultList().get(0);
+    assertThat(batchIssueDto.getKey()).isEqualTo("1000");
+    assertThat(batchIssueDto.getRuleKey()).isEqualTo("AvoidCycle");
+    assertThat(batchIssueDto.getRuleRepo()).isEqualTo("squid");
+    assertThat(batchIssueDto.getMessage()).isEqualTo("Avoid this");
+    assertThat(batchIssueDto.getLine()).isEqualTo(200);
+    assertThat(batchIssueDto.getResolution()).isEqualTo(Issue.RESOLUTION_FALSE_POSITIVE);
+    assertThat(batchIssueDto.getStatus()).isEqualTo(Issue.STATUS_RESOLVED);
+    assertThat(batchIssueDto.getComponentPath()).isEqualTo("src/main/java/Sample.java");
+    assertThat(batchIssueDto.getChecksum()).isEqualTo("123456");
+    assertThat(batchIssueDto.getAssigneeLogin()).isEqualTo("john");
+    assertThat(batchIssueDto.getAssigneeName()).isEqualTo("John Doo");
+  }
+
+  @Test
+  public void select_non_closed_issues_by_project_uuid() {
+    setupData("shared", "select_non_closed_issues_by_project_uuid");
+
+    // ABCD is the root module, we should find all 4 issues
+    DefaultResultHandler handler = new DefaultResultHandler();
+    dao.selectNonClosedIssuesByProjectUuid(session, "ABCD", handler);
+    assertThat(handler.getResultList()).hasSize(4);
+
+    // DBCA is a a simple project with a single file
+    handler = new DefaultResultHandler();
+    dao.selectNonClosedIssuesByProjectUuid(session, "DBCA", handler);
+    assertThat(handler.getResultList()).hasSize(1);
+
+    BatchIssueDto batchIssueDto = (BatchIssueDto) handler.getResultList().get(0);
+    assertThat(batchIssueDto.getKey()).isEqualTo("1000");
+    assertThat(batchIssueDto.getRuleKey()).isEqualTo("AvoidCycle");
+    assertThat(batchIssueDto.getRuleRepo()).isEqualTo("squid");
+    assertThat(batchIssueDto.getMessage()).isEqualTo("Avoid this");
+    assertThat(batchIssueDto.getLine()).isEqualTo(200);
+    assertThat(batchIssueDto.getResolution()).isEqualTo(Issue.RESOLUTION_FALSE_POSITIVE);
+    assertThat(batchIssueDto.getStatus()).isEqualTo(Issue.STATUS_RESOLVED);
+    assertThat(batchIssueDto.getComponentPath()).isEqualTo("src/main/java/Sample.java");
+    assertThat(batchIssueDto.getChecksum()).isEqualTo("123456");
+    assertThat(batchIssueDto.getAssigneeLogin()).isEqualTo("john");
+    assertThat(batchIssueDto.getAssigneeName()).isEqualTo("John Doo");
+  }
+
   @Test
   public void insert() throws Exception {
     IssueDto dto = new IssueDto();
@@ -164,7 +219,7 @@ public class IssueDaoTest extends AbstractDaoTestCase {
     dao.insert(session, dto);
     session.commit();
 
-    checkTables("insert", new String[]{"id"}, "issues");
+    checkTables("insert", new String[] {"id"}, "issues");
   }
 
   @Test
@@ -199,6 +254,6 @@ public class IssueDaoTest extends AbstractDaoTestCase {
     dao.update(session, dto);
     session.commit();
 
-    checkTables("update", new String[]{"id"}, "issues");
+    checkTables("update", new String[] {"id"}, "issues");
   }
 }
index 53441e2b8c0bc64d380eddf4f518777c6a790a89..bc1dd5ba7f94401657efe98f99e6954beb8d3a99 100644 (file)
@@ -404,7 +404,7 @@ public class IssueFilterServiceTest {
     String currentUser = "dave.loper";
     IssueFilterDto sharedFilter = new IssueFilterDto().setId(1L).setName("My filter").setUserLogin(currentUser).setShared(true);
 
-    when(authorizationDao.selectGlobalPermissions(currentUser)).thenReturn(newArrayList(GlobalPermissions.DRY_RUN_EXECUTION));
+    when(authorizationDao.selectGlobalPermissions(currentUser)).thenReturn(newArrayList(GlobalPermissions.PREVIEW_EXECUTION));
     when(issueFilterDao.selectById(1L)).thenReturn(sharedFilter);
 
     try {
@@ -529,7 +529,7 @@ public class IssueFilterServiceTest {
   public void should_execute_from_issue_query() {
     IssueQuery issueQuery = IssueQuery.builder().build();
     QueryContext queryContext = new QueryContext().setPage(2, 50);
-    
+
     Result<Issue> result = mock(Result.class);
     when(result.getHits()).thenReturn(newArrayList((Issue) new DefaultIssue()));
     when(result.getTotal()).thenReturn(100L);
index f6938b9172f24cc4734cce495ab186b8e1e9ffcb..94bd72758c87e738a78ea7f3a8bb90e2d21211f4 100644 (file)
@@ -30,12 +30,7 @@ import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.web.UserRole;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.core.permission.PermissionQuery;
-import org.sonar.core.permission.PermissionTemplateDao;
-import org.sonar.core.permission.PermissionTemplateDto;
-import org.sonar.core.permission.PermissionTemplateGroupDto;
-import org.sonar.core.permission.PermissionTemplateUserDto;
+import org.sonar.core.permission.*;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.properties.PropertiesDao;
@@ -160,15 +155,15 @@ public class InternalPermissionTemplateServiceTest {
 
     List<PermissionTemplateUserDto> usersPermissions = Lists.newArrayList(
       buildUserPermission("user_scan", GlobalPermissions.SCAN_EXECUTION),
-      buildUserPermission("user_dry_run", GlobalPermissions.DRY_RUN_EXECUTION),
+      buildUserPermission("user_dry_run", GlobalPermissions.PREVIEW_EXECUTION),
       buildUserPermission("user_scan_and_dry_run", GlobalPermissions.SCAN_EXECUTION),
-      buildUserPermission("user_scan_and_dry_run", GlobalPermissions.DRY_RUN_EXECUTION)
+      buildUserPermission("user_scan_and_dry_run", GlobalPermissions.PREVIEW_EXECUTION)
       );
 
     List<PermissionTemplateGroupDto> groupsPermissions = Lists.newArrayList(
       buildGroupPermission("admin_group", GlobalPermissions.SYSTEM_ADMIN),
       buildGroupPermission("scan_group", GlobalPermissions.SCAN_EXECUTION),
-      buildGroupPermission(null, GlobalPermissions.DRY_RUN_EXECUTION)
+      buildGroupPermission(null, GlobalPermissions.PREVIEW_EXECUTION)
       );
 
     PermissionTemplateDto permissionTemplateDto = new PermissionTemplateDto()
@@ -184,7 +179,7 @@ public class InternalPermissionTemplateServiceTest {
 
     assertThat(permissionTemplate.getUsersForPermission(GlobalPermissions.DASHBOARD_SHARING)).isEmpty();
     assertThat(permissionTemplate.getUsersForPermission(GlobalPermissions.SCAN_EXECUTION)).extracting("userName").containsOnly("user_scan", "user_scan_and_dry_run");
-    assertThat(permissionTemplate.getUsersForPermission(GlobalPermissions.DRY_RUN_EXECUTION)).extracting("userName").containsOnly("user_dry_run", "user_scan_and_dry_run");
+    assertThat(permissionTemplate.getUsersForPermission(GlobalPermissions.PREVIEW_EXECUTION)).extracting("userName").containsOnly("user_dry_run", "user_scan_and_dry_run");
     assertThat(permissionTemplate.getGroupsForPermission(GlobalPermissions.DASHBOARD_SHARING)).isEmpty();
     assertThat(permissionTemplate.getGroupsForPermission(GlobalPermissions.SCAN_EXECUTION)).extracting("groupName").containsOnly("scan_group");
     assertThat(permissionTemplate.getGroupsForPermission(GlobalPermissions.SYSTEM_ADMIN)).extracting("groupName").containsOnly("admin_group");
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/IssuesActionTest/issues_on_module-expected.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/IssuesActionTest/issues_on_module-expected.json
new file mode 100644 (file)
index 0000000..981ebb2
--- /dev/null
@@ -0,0 +1,16 @@
+[
+  {
+    "key": "EFGH",
+    "componentPath": "src/main/java/Action.java",
+    "ruleKey": "AvoidCycle",
+    "ruleRepo": "squid",
+    "line": 200,
+    "message": "Do not use this method",
+    "resolution": "FALSE-POSITIVE",
+    "status": "RESOLVED",
+    "checksum": "123456",
+    "assigneeLogin": "john",
+    "assigneeFullname": "John Doo"
+  }
+]
+
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/IssuesActionTest/issues_on_project-expected.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/IssuesActionTest/issues_on_project-expected.json
new file mode 100644 (file)
index 0000000..981ebb2
--- /dev/null
@@ -0,0 +1,16 @@
+[
+  {
+    "key": "EFGH",
+    "componentPath": "src/main/java/Action.java",
+    "ruleKey": "AvoidCycle",
+    "ruleRepo": "squid",
+    "line": 200,
+    "message": "Do not use this method",
+    "resolution": "FALSE-POSITIVE",
+    "status": "RESOLVED",
+    "checksum": "123456",
+    "assigneeLogin": "john",
+    "assigneeFullname": "John Doo"
+  }
+]
+
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/IssuesActionTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/batch/IssuesActionTest/shared.xml
new file mode 100644 (file)
index 0000000..2d199b0
--- /dev/null
@@ -0,0 +1,40 @@
+<dataset>
+
+  <!-- Multi module project -->
+  <projects id="399" kee="struts" root_id="[null]" qualifier="TRK" scope="PRJ" uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path="." path="[null]"/>
+  <projects id="400" kee="struts-core" root_id="399" qualifier="BRC" scope="PRJ" uuid="BCDE" project_uuid="ABCD" module_uuid="ABCD" module_uuid_path=".ABCD.BCDE."
+            path="struts-core"/>
+  <projects id="401" kee="Action.java" root_id="400" qualifier="CLA" scope="PRJ" uuid="CDEF" project_uuid="ABCD" module_uuid="BCDE" module_uuid_path=".ABCD.BCDE."
+            path="src/main/java/Action.java"/>
+
+  <rules id="500" tags="[null]" system_tags="[null]" plugin_rule_key="AvoidCycle" plugin_name="squid" language="java"/>
+
+  <users id="10" login="john" name="John Doo" active="[true]"/>
+
+  <!-- Open Issue on a file -->
+  <issues
+      id="100"
+      kee="EFGH"
+      component_id="401"
+      root_component_id="399"
+      rule_id="500"
+      severity="BLOCKER"
+      manual_severity="[false]"
+      message="Do not use this method"
+      line="200"
+      effort_to_fix="[null]"
+      status="RESOLVED"
+      resolution="FALSE-POSITIVE"
+      checksum="123456"
+      reporter="user"
+      assignee="john"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="2013-04-16"
+      issue_update_date="2013-04-16"
+      issue_close_date="2013-04-16"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/select_non_closed_issues_by_module_uuid.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/select_non_closed_issues_by_module_uuid.xml
new file mode 100644 (file)
index 0000000..197ddde
--- /dev/null
@@ -0,0 +1,159 @@
+<dataset>
+
+  <!-- Open Issue on a file -->
+  <issues
+      id="100"
+      kee="100"
+      component_id="401"
+      root_component_id="399"
+      rule_id="500"
+      severity="BLOCKER"
+      manual_severity="[false]"
+      message="[null]"
+      line="200"
+      effort_to_fix="[null]"
+      status="OPEN"
+      resolution="[null]"
+      checksum="[null]"
+      reporter="user"
+      assignee="user"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="2013-04-16"
+      issue_update_date="2013-04-16"
+      issue_close_date="2013-04-16"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+  <!-- Open Issue on a file -->
+  <issues
+      id="101"
+      kee="101"
+      component_id="402"
+      root_component_id="399"
+      rule_id="501"
+      severity="MAJOR"
+      manual_severity="[false]"
+      message="[null]"
+      line="120"
+      effort_to_fix="[null]"
+      status="OPEN"
+      resolution="[null]"
+      checksum="[null]"
+      reporter="[null]"
+      assignee="user"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="2013-04-16"
+      issue_update_date="2013-04-16"
+      issue_close_date="2013-04-16"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+  <!-- Closed Issue on a file -->
+  <issues
+      id="102"
+      kee="102"
+      component_id="402"
+      root_component_id="399"
+      rule_id="501"
+      severity="MAJOR"
+      manual_severity="[false]"
+      message="[null]"
+      line="120"
+      effort_to_fix="[null]"
+      status="CLOSED"
+      resolution="FIXED"
+      checksum="[null]"
+      reporter="[null]"
+      assignee="user"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="2013-04-16"
+      issue_update_date="2013-04-16"
+      issue_close_date="2013-04-16"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+  <!-- Open Issue on a sub module -->
+  <issues
+      id="103"
+      kee="103"
+      component_id="400"
+      root_component_id="399"
+      rule_id="501"
+      severity="MAJOR"
+      manual_severity="[false]"
+      message="[null]"
+      line="[null]"
+      effort_to_fix="[null]"
+      status="OPEN"
+      resolution="[null]"
+      checksum="[null]"
+      reporter="[null]"
+      assignee="user"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="2013-04-16"
+      issue_update_date="2013-04-16"
+      issue_close_date="2013-04-16"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+  <!-- Open Issue on a root module -->
+  <issues
+      id="104"
+      kee="104"
+      component_id="399"
+      root_component_id="399"
+      rule_id="501"
+      severity="MAJOR"
+      manual_severity="[false]"
+      message="[null]"
+      line="[null]"
+      effort_to_fix="[null]"
+      status="OPEN"
+      resolution="[null]"
+      checksum="[null]"
+      reporter="[null]"
+      assignee="user"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="2013-04-16"
+      issue_update_date="2013-04-16"
+      issue_close_date="2013-04-16"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+  <!-- Open Issue on a file of the single project -->
+  <issues
+      id="1000"
+      kee="1000"
+      component_id="1001"
+      root_component_id="1000"
+      rule_id="500"
+      severity="BLOCKER"
+      manual_severity="[false]"
+      message="Avoid this"
+      line="200"
+      effort_to_fix="[null]"
+      status="RESOLVED"
+      resolution="FALSE-POSITIVE"
+      checksum="123456"
+      reporter="user"
+      assignee="john"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="2013-04-16"
+      issue_update_date="2013-04-16"
+      issue_close_date="2013-04-16"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/select_non_closed_issues_by_project_uuid.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/select_non_closed_issues_by_project_uuid.xml
new file mode 100644 (file)
index 0000000..197ddde
--- /dev/null
@@ -0,0 +1,159 @@
+<dataset>
+
+  <!-- Open Issue on a file -->
+  <issues
+      id="100"
+      kee="100"
+      component_id="401"
+      root_component_id="399"
+      rule_id="500"
+      severity="BLOCKER"
+      manual_severity="[false]"
+      message="[null]"
+      line="200"
+      effort_to_fix="[null]"
+      status="OPEN"
+      resolution="[null]"
+      checksum="[null]"
+      reporter="user"
+      assignee="user"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="2013-04-16"
+      issue_update_date="2013-04-16"
+      issue_close_date="2013-04-16"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+  <!-- Open Issue on a file -->
+  <issues
+      id="101"
+      kee="101"
+      component_id="402"
+      root_component_id="399"
+      rule_id="501"
+      severity="MAJOR"
+      manual_severity="[false]"
+      message="[null]"
+      line="120"
+      effort_to_fix="[null]"
+      status="OPEN"
+      resolution="[null]"
+      checksum="[null]"
+      reporter="[null]"
+      assignee="user"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="2013-04-16"
+      issue_update_date="2013-04-16"
+      issue_close_date="2013-04-16"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+  <!-- Closed Issue on a file -->
+  <issues
+      id="102"
+      kee="102"
+      component_id="402"
+      root_component_id="399"
+      rule_id="501"
+      severity="MAJOR"
+      manual_severity="[false]"
+      message="[null]"
+      line="120"
+      effort_to_fix="[null]"
+      status="CLOSED"
+      resolution="FIXED"
+      checksum="[null]"
+      reporter="[null]"
+      assignee="user"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="2013-04-16"
+      issue_update_date="2013-04-16"
+      issue_close_date="2013-04-16"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+  <!-- Open Issue on a sub module -->
+  <issues
+      id="103"
+      kee="103"
+      component_id="400"
+      root_component_id="399"
+      rule_id="501"
+      severity="MAJOR"
+      manual_severity="[false]"
+      message="[null]"
+      line="[null]"
+      effort_to_fix="[null]"
+      status="OPEN"
+      resolution="[null]"
+      checksum="[null]"
+      reporter="[null]"
+      assignee="user"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="2013-04-16"
+      issue_update_date="2013-04-16"
+      issue_close_date="2013-04-16"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+  <!-- Open Issue on a root module -->
+  <issues
+      id="104"
+      kee="104"
+      component_id="399"
+      root_component_id="399"
+      rule_id="501"
+      severity="MAJOR"
+      manual_severity="[false]"
+      message="[null]"
+      line="[null]"
+      effort_to_fix="[null]"
+      status="OPEN"
+      resolution="[null]"
+      checksum="[null]"
+      reporter="[null]"
+      assignee="user"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="2013-04-16"
+      issue_update_date="2013-04-16"
+      issue_close_date="2013-04-16"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+  <!-- Open Issue on a file of the single project -->
+  <issues
+      id="1000"
+      kee="1000"
+      component_id="1001"
+      root_component_id="1000"
+      rule_id="500"
+      severity="BLOCKER"
+      manual_severity="[false]"
+      message="Avoid this"
+      line="200"
+      effort_to_fix="[null]"
+      status="RESOLVED"
+      resolution="FALSE-POSITIVE"
+      checksum="123456"
+      reporter="user"
+      assignee="john"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="2013-04-16"
+      issue_update_date="2013-04-16"
+      issue_close_date="2013-04-16"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+</dataset>
index 44deea3ff9c0b291906262937ed732655a9a4c4f..cae2ab9c007fe31d9f97fc4686929b5851a19a0f 100644 (file)
@@ -2,10 +2,19 @@
 
   <group_roles id="1" group_id="[null]" resource_id="399" role="user"/>
 
-  <projects id="399" kee="struts" root_id="[null]" qualifier="TRK" scope="PRJ" uuid="ABCD"/>
-  <projects id="400" kee="struts-core" root_id="399" qualifier="BRC" scope="PRJ" uuid="BCDE"/>
-  <projects id="401" kee="Action.java" root_id="400" qualifier="CLA" scope="PRJ" uuid="CDEF"/>
-  <projects id="402" kee="Filter.java" root_id="400" qualifier="CLA" scope="PRJ" uuid="DEFG"/>
+  <!-- Multi module project -->
+  <projects id="399" kee="struts" root_id="[null]" qualifier="TRK" scope="PRJ" uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path="." path="[null]"/>
+  <projects id="400" kee="struts-core" root_id="399" qualifier="BRC" scope="PRJ" uuid="BCDE" project_uuid="ABCD" module_uuid="ABCD" module_uuid_path=".ABCD.BCDE."
+            path="struts-core"/>
+  <projects id="401" kee="Action.java" root_id="400" qualifier="CLA" scope="PRJ" uuid="CDEF" project_uuid="ABCD" module_uuid="BCDE" module_uuid_path=".ABCD.BCDE."
+            path="src/main/java/Action.java"/>
+  <projects id="402" kee="Filter.java" root_id="400" qualifier="CLA" scope="PRJ" uuid="DEFG" project_uuid="ABCD" module_uuid="BCDE" module_uuid_path=".ABCD.BCDE."
+            path="src/main/java/Filter.java"/>
+
+  <!-- Single project -->
+  <projects id="1000" kee="sample" root_id="[null]" qualifier="TRK" scope="PRJ" uuid="DBCA" project_uuid="DBCA" module_uuid="[null]" module_uuid_path="."/>
+  <projects id="1001" kee="Sample.java" root_id="1000" qualifier="CLA" scope="PRJ" uuid="EDCB" project_uuid="DBCA" module_uuid="DBCA" module_uuid_path=".DBCA."
+            path="src/main/java/Sample.java"/>
 
   <snapshots id="100" project_id="399" root_snapshot_id="[null]" parent_snapshot_id="[null]" root_project_id="399"
              path="" islast="[true]"/>
@@ -19,4 +28,6 @@
   <rules id="500" tags="[null]" system_tags="[null]" plugin_rule_key="AvoidCycle" plugin_name="squid" language="java"/>
   <rules id="501" tags="[null]" system_tags="[null]" plugin_rule_key="NullRef" plugin_name="squid" language="xoo"/>
 
+  <users id="1" login="john" name="John Doo" active="[true]"/>
+
 </dataset>
index 576cb9105a326f60d1b872d7bd6542b06ac44b22..14e4e4a378527c2862581c5b4ae2d9625eae3681 100644 (file)
@@ -26,39 +26,47 @@ import org.sonar.batch.protocol.GsonHelper;
 
 import javax.annotation.Nullable;
 
+import java.io.Closeable;
 import java.io.IOException;
 import java.io.Reader;
 import java.io.Writer;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
-public class PreviousIssueHelper {
+public class PreviousIssueHelper implements Closeable {
 
   private final Gson gson = GsonHelper.create();
+  JsonWriter writer;
 
-  private PreviousIssueHelper() {
+  private PreviousIssueHelper(Writer out) {
+    try {
+      this.writer = new JsonWriter(out);
+      writer.setIndent("  ");
+      writer.beginArray();
+    } catch (IOException e) {
+      throw new IllegalStateException("Unable to open writer", e);
+    }
   }
 
-  public static PreviousIssueHelper create() {
-    return new PreviousIssueHelper();
+  public static PreviousIssueHelper create(Writer out) {
+    return new PreviousIssueHelper(out);
   }
 
   public static interface Function<F, T> {
     T apply(@Nullable F from);
   }
 
-  public <G> void streamIssues(Writer out, Iterable<G> issues, Function<G, PreviousIssue> converter) {
+  public <G> void addIssue(G issue, Function<G, PreviousIssue> converter) {
+    gson.toJson(converter.apply(issue), PreviousIssue.class, writer);
+  }
+
+  @Override
+  public void close() {
     try {
-      JsonWriter writer = new JsonWriter(out);
-      writer.setIndent("  ");
-      writer.beginArray();
-      for (G issue : issues) {
-        gson.toJson(converter.apply(issue), PreviousIssue.class, writer);
-      }
       writer.endArray();
       writer.close();
     } catch (IOException e) {
-      throw new IllegalStateException("Unable to stream issues", e);
+      throw new IllegalStateException("Unable to close write", e);
     }
   }
 
index 8719db821f80bf7fa3323e83f304e8957a75b088..1e5264b4ad29193a0f4928994ff7acba3879d79f 100644 (file)
@@ -25,7 +25,6 @@ import org.skyscreamer.jsonassert.JSONAssert;
 
 import java.io.StringReader;
 import java.io.StringWriter;
-import java.util.Arrays;
 import java.util.Iterator;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -34,8 +33,8 @@ public class PreviousIssueHelperTest {
 
   @Test
   public void writeIssues() throws JSONException {
-    PreviousIssueHelper helper = PreviousIssueHelper.create();
     StringWriter out = new StringWriter();
+    PreviousIssueHelper helper = PreviousIssueHelper.create(out);
 
     PreviousIssue issue1 = new PreviousIssue();
     issue1.setKey("key1");
@@ -52,12 +51,10 @@ public class PreviousIssueHelperTest {
     PreviousIssue issue2 = new PreviousIssue();
     issue2.setKey("key2");
 
-    helper.streamIssues(out, Arrays.asList(issue1, issue2), new PreviousIssueHelper.Function<PreviousIssue, PreviousIssue>() {
-      @Override
-      public PreviousIssue apply(PreviousIssue from) {
-        return from;
-      }
-    });
+    PreviousIssueFunction previousIssueFunction = new PreviousIssueFunction();
+    helper.addIssue(issue1, previousIssueFunction);
+    helper.addIssue(issue2, previousIssueFunction);
+    helper.close();
 
     JSONAssert
       .assertEquals(
@@ -65,11 +62,20 @@ public class PreviousIssueHelperTest {
           +
           "{\"key\": \"key2\"}]",
         out.getBuffer().toString(), true);
+
+  }
+
+  private static class PreviousIssueFunction implements PreviousIssueHelper.Function<PreviousIssue, PreviousIssue> {
+    @Override
+    public PreviousIssue apply(PreviousIssue from) {
+      return from;
+    }
   }
 
   @Test
   public void readIssues() {
-    PreviousIssueHelper helper = PreviousIssueHelper.create();
+    StringWriter out = new StringWriter();
+    PreviousIssueHelper helper = PreviousIssueHelper.create(out);
     StringReader reader = new StringReader(
       "[{\"key\": \"key1\", \"componentPath\": \"path\", \"ruleKey\": \"rulekey\", \"ruleRepo\": \"repokey\", \"line\": 2,\"message\": \"message\", \"severity\": \"severity\", \"resolution\": \"resolution\", \"status\": \"status\", \"checksum\": \"checksum\",\"assigneeLogin\": \"login\", \"assigneeFullname\": \"fullname\"},"
         +
@@ -95,6 +101,7 @@ public class PreviousIssueHelperTest {
     assertThat(issue1.assigneeFullname()).isEqualTo("fullname");
 
     assertThat(issue2.key()).isEqualTo("key2");
+    helper.close();
   }
 
 }
index f5e887bde589c781b67f1fe7489b4c6921098877..87f4799525ee70d8e0022622ebb4a32b02fc0e14 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.core.component;
 
 import org.sonar.api.component.Component;
+import org.sonar.api.resources.Scopes;
 import org.sonar.core.persistence.Dto;
 
 import javax.annotation.CheckForNull;
@@ -223,6 +224,10 @@ public class ComponentDto extends Dto<String> implements Component {
     return this;
   }
 
+  public boolean isRootProject() {
+    return MODULE_UUID_PATH_SEP.equals(moduleUuidPath) && Scopes.PROJECT.equals(scope);
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/BatchIssueDto.java b/sonar-core/src/main/java/org/sonar/core/issue/db/BatchIssueDto.java
new file mode 100644 (file)
index 0000000..2f2343e
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.core.issue.db;
+
+public class BatchIssueDto {
+
+  private String kee;
+  private String message;
+  private Integer line;
+  private String status;
+  private String resolution;
+  private String checksum;
+  private String assigneeLogin;
+  private String assigneeName;
+  private String componentPath;
+  private String ruleKey;
+  private String ruleRepo;
+
+  public String getAssigneeLogin() {
+    return assigneeLogin;
+  }
+
+  public BatchIssueDto setAssigneeLogin(String assigneeLogin) {
+    this.assigneeLogin = assigneeLogin;
+    return this;
+  }
+
+  public String getAssigneeName() {
+    return assigneeName;
+  }
+
+  public BatchIssueDto setAssigneeName(String assigneeName) {
+    this.assigneeName = assigneeName;
+    return this;
+  }
+
+  public String getChecksum() {
+    return checksum;
+  }
+
+  public BatchIssueDto setChecksum(String checksum) {
+    this.checksum = checksum;
+    return this;
+  }
+
+  public String getComponentPath() {
+    return componentPath;
+  }
+
+  public BatchIssueDto setComponentPath(String componentPath) {
+    this.componentPath = componentPath;
+    return this;
+  }
+
+  public String getKey() {
+    return kee;
+  }
+
+  public BatchIssueDto setKey(String key) {
+    this.kee = key;
+    return this;
+  }
+
+  public Integer getLine() {
+    return line;
+  }
+
+  public BatchIssueDto setLine(Integer line) {
+    this.line = line;
+    return this;
+  }
+
+  public String getMessage() {
+    return message;
+  }
+
+  public BatchIssueDto setMessage(String message) {
+    this.message = message;
+    return this;
+  }
+
+  public String getResolution() {
+    return resolution;
+  }
+
+  public BatchIssueDto setResolution(String resolution) {
+    this.resolution = resolution;
+    return this;
+  }
+
+  public String getRuleKey() {
+    return ruleKey;
+  }
+
+  public BatchIssueDto setRuleKey(String ruleKey) {
+    this.ruleKey = ruleKey;
+    return this;
+  }
+
+  public String getRuleRepo() {
+    return ruleRepo;
+  }
+
+  public BatchIssueDto setRuleRepo(String ruleRepo) {
+    this.ruleRepo = ruleRepo;
+    return this;
+  }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public BatchIssueDto setStatus(String status) {
+    this.status = status;
+    return this;
+  }
+}
index d8a8d5a5f95f178a05716c817e59aefc3b4c49fa..b9893ad1c500d039e2feb8088a1076c87c3ad576 100644 (file)
@@ -34,13 +34,13 @@ public final class GlobalPermissions {
   public static final String QUALITY_PROFILE_ADMIN = "profileadmin";
   public static final String DASHBOARD_SHARING = "shareDashboard";
   public static final String SCAN_EXECUTION = "scan";
-  public static final String DRY_RUN_EXECUTION = "dryRunScan";
+  public static final String PREVIEW_EXECUTION = "dryRunScan";
   public static final String PROVISIONING = "provisioning";
 
   /**
    * All the global permissions values, ordered from {@link #SYSTEM_ADMIN} to {@link #PROVISIONING}.
    */
-  public static final List<String> ALL = ImmutableList.of(SYSTEM_ADMIN, QUALITY_PROFILE_ADMIN, DASHBOARD_SHARING, SCAN_EXECUTION, DRY_RUN_EXECUTION, PROVISIONING);
+  public static final List<String> ALL = ImmutableList.of(SYSTEM_ADMIN, QUALITY_PROFILE_ADMIN, DASHBOARD_SHARING, SCAN_EXECUTION, PREVIEW_EXECUTION, PROVISIONING);
 
   private GlobalPermissions() {
     // only static methods
index 62e559e59fc00716e9bcea778c4cdacaa7fe58b2..75f75cf9089ab321a59320b7b18c34d0761503b0 100644 (file)
@@ -25,11 +25,7 @@ import com.google.common.io.Closeables;
 import org.apache.ibatis.builder.xml.XMLMapperBuilder;
 import org.apache.ibatis.logging.LogFactory;
 import org.apache.ibatis.mapping.Environment;
-import org.apache.ibatis.session.Configuration;
-import org.apache.ibatis.session.ExecutorType;
-import org.apache.ibatis.session.SqlSession;
-import org.apache.ibatis.session.SqlSessionFactory;
-import org.apache.ibatis.session.SqlSessionFactoryBuilder;
+import org.apache.ibatis.session.*;
 import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
 import org.apache.ibatis.type.JdbcType;
 import org.slf4j.LoggerFactory;
@@ -47,14 +43,7 @@ import org.sonar.core.component.db.SnapshotMapper;
 import org.sonar.core.computation.db.AnalysisReportDto;
 import org.sonar.core.computation.db.AnalysisReportMapper;
 import org.sonar.core.config.Logback;
-import org.sonar.core.dashboard.ActiveDashboardDto;
-import org.sonar.core.dashboard.ActiveDashboardMapper;
-import org.sonar.core.dashboard.DashboardDto;
-import org.sonar.core.dashboard.DashboardMapper;
-import org.sonar.core.dashboard.WidgetDto;
-import org.sonar.core.dashboard.WidgetMapper;
-import org.sonar.core.dashboard.WidgetPropertyDto;
-import org.sonar.core.dashboard.WidgetPropertyMapper;
+import org.sonar.core.dashboard.*;
 import org.sonar.core.dependency.DependencyDto;
 import org.sonar.core.dependency.DependencyMapper;
 import org.sonar.core.dependency.ResourceSnapshotDto;
@@ -63,32 +52,11 @@ import org.sonar.core.duplication.DuplicationMapper;
 import org.sonar.core.duplication.DuplicationUnitDto;
 import org.sonar.core.graph.jdbc.GraphDto;
 import org.sonar.core.graph.jdbc.GraphDtoMapper;
-import org.sonar.core.issue.db.ActionPlanDto;
-import org.sonar.core.issue.db.ActionPlanMapper;
-import org.sonar.core.issue.db.ActionPlanStatsDto;
-import org.sonar.core.issue.db.ActionPlanStatsMapper;
-import org.sonar.core.issue.db.IssueChangeDto;
-import org.sonar.core.issue.db.IssueChangeMapper;
-import org.sonar.core.issue.db.IssueDto;
-import org.sonar.core.issue.db.IssueFilterDto;
-import org.sonar.core.issue.db.IssueFilterFavouriteDto;
-import org.sonar.core.issue.db.IssueFilterFavouriteMapper;
-import org.sonar.core.issue.db.IssueFilterMapper;
-import org.sonar.core.issue.db.IssueMapper;
-import org.sonar.core.measure.db.MeasureDto;
-import org.sonar.core.measure.db.MeasureFilterDto;
-import org.sonar.core.measure.db.MeasureFilterMapper;
-import org.sonar.core.measure.db.MeasureMapper;
-import org.sonar.core.measure.db.MetricDto;
-import org.sonar.core.measure.db.MetricMapper;
+import org.sonar.core.issue.db.*;
+import org.sonar.core.measure.db.*;
 import org.sonar.core.notification.db.NotificationQueueDto;
 import org.sonar.core.notification.db.NotificationQueueMapper;
-import org.sonar.core.permission.GroupWithPermissionDto;
-import org.sonar.core.permission.PermissionTemplateDto;
-import org.sonar.core.permission.PermissionTemplateGroupDto;
-import org.sonar.core.permission.PermissionTemplateMapper;
-import org.sonar.core.permission.PermissionTemplateUserDto;
-import org.sonar.core.permission.UserWithPermissionDto;
+import org.sonar.core.permission.*;
 import org.sonar.core.persistence.dialect.Dialect;
 import org.sonar.core.persistence.migration.v44.Migration44Mapper;
 import org.sonar.core.persistence.migration.v45.Migration45Mapper;
@@ -98,22 +66,9 @@ import org.sonar.core.properties.PropertyDto;
 import org.sonar.core.purge.IdUuidPair;
 import org.sonar.core.purge.PurgeMapper;
 import org.sonar.core.purge.PurgeableSnapshotDto;
-import org.sonar.core.qualitygate.db.ProjectQgateAssociationDto;
-import org.sonar.core.qualitygate.db.ProjectQgateAssociationMapper;
-import org.sonar.core.qualitygate.db.QualityGateConditionDto;
-import org.sonar.core.qualitygate.db.QualityGateConditionMapper;
-import org.sonar.core.qualitygate.db.QualityGateDto;
-import org.sonar.core.qualitygate.db.QualityGateMapper;
-import org.sonar.core.qualityprofile.db.ActiveRuleDto;
-import org.sonar.core.qualityprofile.db.ActiveRuleMapper;
-import org.sonar.core.qualityprofile.db.ActiveRuleParamDto;
-import org.sonar.core.qualityprofile.db.QualityProfileDto;
-import org.sonar.core.qualityprofile.db.QualityProfileMapper;
-import org.sonar.core.resource.ResourceDto;
-import org.sonar.core.resource.ResourceIndexDto;
-import org.sonar.core.resource.ResourceIndexerMapper;
-import org.sonar.core.resource.ResourceKeyUpdaterMapper;
-import org.sonar.core.resource.ResourceMapper;
+import org.sonar.core.qualitygate.db.*;
+import org.sonar.core.qualityprofile.db.*;
+import org.sonar.core.resource.*;
 import org.sonar.core.rule.RuleDto;
 import org.sonar.core.rule.RuleMapper;
 import org.sonar.core.rule.RuleParamDto;
@@ -123,19 +78,7 @@ import org.sonar.core.technicaldebt.db.CharacteristicMapper;
 import org.sonar.core.technicaldebt.db.RequirementMigrationDto;
 import org.sonar.core.template.LoadedTemplateDto;
 import org.sonar.core.template.LoadedTemplateMapper;
-import org.sonar.core.user.AuthorDto;
-import org.sonar.core.user.AuthorMapper;
-import org.sonar.core.user.GroupDto;
-import org.sonar.core.user.GroupMapper;
-import org.sonar.core.user.GroupMembershipDto;
-import org.sonar.core.user.GroupMembershipMapper;
-import org.sonar.core.user.GroupRoleDto;
-import org.sonar.core.user.RoleMapper;
-import org.sonar.core.user.UserDto;
-import org.sonar.core.user.UserGroupDto;
-import org.sonar.core.user.UserGroupMapper;
-import org.sonar.core.user.UserMapper;
-import org.sonar.core.user.UserRoleDto;
+import org.sonar.core.user.*;
 
 import java.io.InputStream;
 
@@ -218,6 +161,7 @@ public class MyBatis implements BatchComponent, ServerComponent {
     loadAlias(conf, "Measure", MeasureDto.class);
     loadAlias(conf, "Metric", MetricDto.class);
     loadAlias(conf, "Issue", IssueDto.class);
+    loadAlias(conf, "BatchIssue", BatchIssueDto.class);
     loadAlias(conf, "IssueChange", IssueChangeDto.class);
     loadAlias(conf, "IssueFilter", IssueFilterDto.class);
     loadAlias(conf, "IssueFilterFavourite", IssueFilterFavouriteDto.class);
index 7453e1afa1a105636415fddf9d2e21fad5d4c3de..2156d2c6b74984c319217a905a47bd802679ac90 100644 (file)
     p.kee as componentKey,
     root.kee as projectKey
     from issues i
-    inner join (select p.id,p.kee from projects p where (p.root_id=#{id} and p.qualifier &lt;&gt; 'BRC') or
-    (p.id=#{id})) p on p.id=i.component_id
+    inner join (select p.id,p.kee from projects p where (p.root_id=#{id} and p.qualifier &lt;&gt; 'BRC') or (p.id=#{id})) p on p.id=i.component_id
     inner join rules r on r.id=i.rule_id
     left outer join projects root on root.id=i.root_component_id
     where i.status &lt;&gt; 'CLOSED'
   </select>
 
+  <select id="selectNonClosedIssuesByModuleUuid" parameterType="String" resultType="BatchIssue">
+    SELECT
+    i.kee as kee,
+    i.message as message,
+    i.line as line,
+    i.status as status,
+    i.resolution as resolution,
+    i.checksum as checksum,
+    r.plugin_rule_key as ruleKey,
+    r.plugin_name as ruleRepo,
+    component.path as componentPath,
+    i.assignee as assigneeLogin,
+    u.name as assigneeName
+    FROM issues i
+    INNER JOIN (SELECT p.id,p.path FROM projects p WHERE p.module_uuid=#{uuid} OR p.uuid=#{uuid}) component ON component.id=i.component_id
+    INNER JOIN rules r ON r.id=i.rule_id
+    LEFT OUTER JOIN users u ON u.login=i.assignee
+    WHERE i.status &lt;&gt; 'CLOSED'
+  </select>
+
+  <select id="selectNonClosedIssuesByProjectUuid" parameterType="String" resultType="BatchIssue">
+    SELECT
+    i.kee as kee,
+    i.message as message,
+    i.line as line,
+    i.status as status,
+    i.resolution as resolution,
+    i.checksum as checksum,
+    r.plugin_rule_key as ruleKey,
+    r.plugin_name as ruleRepo,
+    component.path as componentPath,
+    i.assignee as assigneeLogin,
+    u.name as assigneeName
+    FROM issues i
+    INNER JOIN projects component on component.id=i.component_id
+    INNER JOIN projects project on project.uuid=component.project_uuid AND project.uuid=#{uuid}
+    INNER JOIN rules r ON r.id=i.rule_id
+    LEFT OUTER JOIN users u ON u.login=i.assignee
+    WHERE i.status &lt;&gt; 'CLOSED'
+  </select>
+
   <select id="selectByKeys" parameterType="map" resultType="Issue">
     select
     <include refid="issueColumns"/>
index 0895598841db20bd7c90d03606375de1a7a7c522..d3f0051d8eededf404ead2001c99c177ec072112 100644 (file)
@@ -69,11 +69,11 @@ public class RoleDaoTest extends AbstractDaoTestCase {
     setupData("globalGroupPermissions");
 
     assertThat(dao.selectGroupPermissions(session, "sonar-administrators", null)).containsOnly(GlobalPermissions.SYSTEM_ADMIN, GlobalPermissions.QUALITY_PROFILE_ADMIN,
-        GlobalPermissions.DASHBOARD_SHARING);
+      GlobalPermissions.DASHBOARD_SHARING);
     assertThat(dao.selectGroupPermissions(session, "sonar-users", null)).containsOnly(GlobalPermissions.DASHBOARD_SHARING);
-    assertThat(dao.selectGroupPermissions(session, DefaultGroups.ANYONE, null)).containsOnly(GlobalPermissions.DRY_RUN_EXECUTION, GlobalPermissions.SCAN_EXECUTION);
-    assertThat(dao.selectGroupPermissions(session, "anyone", null)).containsOnly(GlobalPermissions.DRY_RUN_EXECUTION, GlobalPermissions.SCAN_EXECUTION);
-    assertThat(dao.selectGroupPermissions(session, "AnYoNe", null)).containsOnly(GlobalPermissions.DRY_RUN_EXECUTION, GlobalPermissions.SCAN_EXECUTION);
+    assertThat(dao.selectGroupPermissions(session, DefaultGroups.ANYONE, null)).containsOnly(GlobalPermissions.PREVIEW_EXECUTION, GlobalPermissions.SCAN_EXECUTION);
+    assertThat(dao.selectGroupPermissions(session, "anyone", null)).containsOnly(GlobalPermissions.PREVIEW_EXECUTION, GlobalPermissions.SCAN_EXECUTION);
+    assertThat(dao.selectGroupPermissions(session, "AnYoNe", null)).containsOnly(GlobalPermissions.PREVIEW_EXECUTION, GlobalPermissions.SCAN_EXECUTION);
   }
 
   @Test