]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9551 Web services handles APP qualifier
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Thu, 20 Jul 2017 13:26:03 +0000 (15:26 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 31 Jul 2017 09:27:51 +0000 (11:27 +0200)
27 files changed:
server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java
server/sonar-server/src/main/java/org/sonar/server/component/ws/ComponentDtoToWsComponent.java
server/sonar-server/src/main/java/org/sonar/server/component/ws/SuggestionCategory.java
server/sonar-server/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java
server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryFactory.java
server/sonar-server/src/main/java/org/sonar/server/measure/ws/SearchAction.java
server/sonar-server/src/main/java/org/sonar/server/permission/index/PermissionIndexerDao.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/template/SearchTemplatesAction.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/template/SetDefaultTemplateAction.java
server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java
server/sonar-server/src/main/java/org/sonar/server/project/ws/UpdateVisibilityAction.java
server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingValidations.java
server/sonar-server/src/main/java/org/sonar/server/ui/ws/ComponentAction.java
server/sonar-server/src/main/java/org/sonar/server/ws/WsParameterBuilder.java
server/sonar-server/src/main/resources/org/sonar/server/component/ws/components-example-suggestions.json [deleted file]
server/sonar-server/src/main/resources/org/sonar/server/component/ws/suggestions-example.json [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/batch/ProjectDataLoaderTest.java
server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ws/SuggestionsActionTest.java
server/sonar-server/src/test/java/org/sonar/server/measure/ws/SearchActionTest.java
server/sonar-server/src/test/java/org/sonar/server/organization/ws/DeleteActionTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/index/PermissionIndexerDaoTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/BasePermissionWsTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/template/SetDefaultTemplateActionTest.java
server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java
server/sonar-server/src/test/java/org/sonar/server/project/ws/UpdateVisibilityActionTest.java

index 2e034f91dae58973bc825f287883e3e218de95f2..1a573ad89a5ef2edca3573a306533747a1bfe033 100644 (file)
@@ -69,7 +69,7 @@ import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_TYPE;
 
 public class ActivityAction implements CeWsAction {
   private static final int MAX_PAGE_SIZE = 1000;
-  private static final List<String> POSSIBLE_QUALIFIERS = ImmutableList.of(Qualifiers.PROJECT, Qualifiers.VIEW, "DEV", Qualifiers.MODULE);
+  private static final List<String> POSSIBLE_QUALIFIERS = ImmutableList.of(Qualifiers.PROJECT, Qualifiers.APP, Qualifiers.VIEW, "DEV", Qualifiers.MODULE);
 
   private final UserSession userSession;
   private final DbClient dbClient;
index eec80dc60e82e6f7d32a51d0431c634d7b4e526b..d7bf90d0e2e9fbed19d30639f944c415f9415168 100644 (file)
@@ -40,7 +40,7 @@ class ComponentDtoToWsComponent {
   /**
    * The concept of "visibility" will only be configured for these qualifiers.
    */
-  private static final Set<String> QUALIFIERS_WITH_VISIBILITY = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.VIEW);
+  private static final Set<String> QUALIFIERS_WITH_VISIBILITY = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.VIEW, Qualifiers.APP);
 
   private ComponentDtoToWsComponent() {
     // prevent instantiation
index a4fd5e5c9e94d05dc0e4e0c418c6bc9af16e4934..8c177983accbb43e2ef980f1ac114242861bea8f 100644 (file)
@@ -27,6 +27,7 @@ import static java.util.Arrays.stream;
 public enum SuggestionCategory {
   VIEW(Qualifiers.VIEW),
   SUBVIEW(Qualifiers.SUBVIEW),
+  APP(Qualifiers.APP),
   PROJECT(Qualifiers.PROJECT),
   MODULE(Qualifiers.MODULE),
   FILE(Qualifiers.FILE),
index 00df270a2750c9738a79c998f9c03eefc6f9bcd3..b770207aa559b179c2d3e7d140e817d33ffd38ab 100644 (file)
@@ -117,7 +117,7 @@ public class SuggestionsAction implements ComponentsWsAction {
       .setSince("4.2")
       .setInternal(true)
       .setHandler(this)
-      .setResponseExample(Resources.getResource(this.getClass(), "components-example-suggestions.json"))
+      .setResponseExample(Resources.getResource(this.getClass(), "suggestions-example.json"))
       .setChangelog(new Change("6.4", "Parameter 's' is optional"));
 
     action.createParam(PARAM_QUERY)
index 6c95b348096e2e355ccd6d3ae35b22a750e68510..b988c3d65c7dc49d90ec3729bef814cb49f7c9e1 100644 (file)
@@ -25,6 +25,7 @@ import com.google.common.base.Splitter;
 import com.google.common.base.Strings;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -35,6 +36,7 @@ import java.util.Locale;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.apache.commons.lang.BooleanUtils;
@@ -292,6 +294,7 @@ public class IssueQueryFactory {
     switch (qualifier) {
       case Qualifiers.VIEW:
       case Qualifiers.SUBVIEW:
+      case Qualifiers.APP:
         addViewsOrSubViews(builder, componentUuids);
         break;
       case Qualifiers.PROJECT:
@@ -313,12 +316,10 @@ public class IssueQueryFactory {
   }
 
   private void addViewsOrSubViews(IssueQuery.Builder builder, Collection<String> viewOrSubViewUuids) {
-    List<String> filteredViewUuids = new ArrayList<>();
-    for (String viewUuid : viewOrSubViewUuids) {
-      if (userSession.hasComponentUuidPermission(UserRole.USER, viewUuid)) {
-        filteredViewUuids.add(viewUuid);
-      }
-    }
+    List<String> filteredViewUuids = viewOrSubViewUuids.stream()
+      .filter(uuid -> userSession.hasComponentUuidPermission(UserRole.USER, uuid))
+      .collect(Collectors.toList());
+
     if (filteredViewUuids.isEmpty()) {
       filteredViewUuids.add(UNKNOWN);
     }
index 6c216afb2140e58732e6aa8db94afd1dde21c591..cba61152db2950f2e0d8f6252d8ef4c187a3f6a6 100644 (file)
@@ -45,6 +45,7 @@ import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Comparator.comparing;
 import static java.util.function.Function.identity;
 import static java.util.stream.Collectors.toMap;
+import static org.sonar.api.resources.Qualifiers.APP;
 import static org.sonar.api.resources.Qualifiers.PROJECT;
 import static org.sonar.api.resources.Qualifiers.SUBVIEW;
 import static org.sonar.api.resources.Qualifiers.VIEW;
@@ -60,7 +61,7 @@ import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_PROJECT
 
 public class SearchAction implements MeasuresWsAction {
 
-  private static final Set<String> ALLOWED_QUALIFIERS = ImmutableSet.of(PROJECT, VIEW, SUBVIEW);
+  private static final Set<String> ALLOWED_QUALIFIERS = ImmutableSet.of(PROJECT, APP, VIEW, SUBVIEW);
 
   private final UserSession userSession;
   private final DbClient dbClient;
index 3f7f595189652c6bfca4018d5ad0338c54d0f4ec..e49d5a9b784239b99ae7e629a671c1fcb20b4c5b 100644 (file)
@@ -110,7 +110,9 @@ public class PermissionIndexerDao {
     "      FROM projects " +
     "      INNER JOIN user_roles ON user_roles.resource_id = projects.id AND user_roles.role = 'user' " +
     "      WHERE " +
-    "        (projects.qualifier = 'TRK' or  projects.qualifier = 'VW') " +
+    "        (projects.qualifier = 'TRK' " +
+    "         or  projects.qualifier = 'VW' " +
+    "         or  projects.qualifier = 'APP') " +
     "        AND projects.copy_component_uuid is NULL " +
     "        {projectsCondition} " +
     "      UNION " +
@@ -126,7 +128,9 @@ public class PermissionIndexerDao {
     "      INNER JOIN group_roles ON group_roles.resource_id = projects.id AND group_roles.role = 'user' " +
     "      INNER JOIN groups ON groups.id = group_roles.group_id " +
     "      WHERE " +
-    "        (projects.qualifier = 'TRK' or  projects.qualifier = 'VW') " +
+    "        (projects.qualifier = 'TRK' " +
+    "         or  projects.qualifier = 'VW' " +
+    "         or  projects.qualifier = 'APP') " +
     "        AND projects.copy_component_uuid is NULL " +
     "        {projectsCondition} " +
     "        AND group_id IS NOT NULL " +
@@ -141,7 +145,9 @@ public class PermissionIndexerDao {
     "      NULL     AS group_id " +
     "      FROM projects " +
     "      WHERE " +
-    "        (projects.qualifier = 'TRK' or  projects.qualifier = 'VW') " +
+    "        (projects.qualifier = 'TRK' " +
+    "         or  projects.qualifier = 'VW' " +
+    "         or  projects.qualifier = 'APP') " +
     "        AND projects.copy_component_uuid is NULL " +
     "        AND projects.private = ? " +
     "        {projectsCondition} " +
@@ -155,7 +161,9 @@ public class PermissionIndexerDao {
     "      NULL  AS group_id " +
     "      FROM projects " +
     "      WHERE " +
-    "        (projects.qualifier = 'TRK' or  projects.qualifier = 'VW') " +
+    "        (projects.qualifier = 'TRK' " +
+    "         or  projects.qualifier = 'VW' " +
+    "         or  projects.qualifier = 'APP') " +
     "        AND projects.copy_component_uuid is NULL " +
     "        AND projects.private = ? " +
     "        {projectsCondition} " +
index f1159aeade578d9bf17d4fe36e24047efec4cb59..a07dfe369f741e625cb79a9dedb94b8bd86a25e7 100644 (file)
@@ -66,6 +66,33 @@ public class SearchTemplatesAction implements PermissionsWsAction {
     this.dataLoader = dataLoader;
   }
 
+  @Override
+  public void define(WebService.NewController context) {
+    WebService.NewAction action = context.createAction("search_templates")
+      .setDescription("List permission templates.<br />" +
+        "Requires the following permission: 'Administer System'.")
+      .setResponseExample(getClass().getResource("search_templates-example.json"))
+      .setSince("5.2")
+      .addSearchQuery("defau", "permission template names")
+      .setHandler(this);
+
+    createOrganizationParameter(action).setSince("6.2");
+  }
+
+  @Override
+  public void handle(Request wsRequest, Response wsResponse) throws Exception {
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      OrganizationDto org = support.findOrganization(dbSession, wsRequest.param(PARAM_ORGANIZATION));
+      SearchTemplatesWsRequest request = new SearchTemplatesWsRequest()
+        .setOrganizationUuid(org.getUuid())
+        .setQuery(wsRequest.param(Param.TEXT_QUERY));
+      checkGlobalAdmin(userSession, request.getOrganizationUuid());
+
+      SearchTemplatesWsResponse searchTemplatesWsResponse = buildResponse(dataLoader.load(dbSession, request));
+      writeProtobuf(searchTemplatesWsResponse, wsRequest, wsResponse);
+    }
+  }
+
   private static void buildDefaultTemplatesResponse(SearchTemplatesWsResponse.Builder response, SearchTemplatesData data) {
     TemplateIdQualifier.Builder templateUuidQualifierBuilder = TemplateIdQualifier.newBuilder();
 
@@ -108,33 +135,6 @@ public class SearchTemplatesAction implements PermissionsWsAction {
     }
   }
 
-  @Override
-  public void define(WebService.NewController context) {
-    WebService.NewAction action = context.createAction("search_templates")
-      .setDescription("List permission templates.<br />" +
-        "Requires the following permission: 'Administer System'.")
-      .setResponseExample(getClass().getResource("search_templates-example.json"))
-      .setSince("5.2")
-      .addSearchQuery("defau", "permission template names")
-      .setHandler(this);
-
-    createOrganizationParameter(action).setSince("6.2");
-  }
-
-  @Override
-  public void handle(Request wsRequest, Response wsResponse) throws Exception {
-    try (DbSession dbSession = dbClient.openSession(false)) {
-      OrganizationDto org = support.findOrganization(dbSession, wsRequest.param(PARAM_ORGANIZATION));
-      SearchTemplatesWsRequest request = new SearchTemplatesWsRequest()
-        .setOrganizationUuid(org.getUuid())
-        .setQuery(wsRequest.param(Param.TEXT_QUERY));
-      checkGlobalAdmin(userSession, request.getOrganizationUuid());
-
-      SearchTemplatesWsResponse searchTemplatesWsResponse = buildResponse(dataLoader.load(dbSession, request));
-      writeProtobuf(searchTemplatesWsResponse, wsRequest, wsResponse);
-    }
-  }
-
   private WsPermissions.SearchTemplatesWsResponse buildResponse(SearchTemplatesData data) {
     SearchTemplatesWsResponse.Builder response = SearchTemplatesWsResponse.newBuilder();
 
index 357c114818514381613738e0051e040b2ed58a35..49eca0a59ffe13ffef01db94d8b58c6d8e29d5bd 100644 (file)
@@ -39,8 +39,8 @@ import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobal
 import static org.sonar.server.permission.ws.PermissionRequestValidator.validateQualifier;
 import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createTemplateParameters;
 import static org.sonar.server.permission.ws.template.WsTemplateRef.newTemplateRef;
-import static org.sonar.server.ws.WsParameterBuilder.createRootQualifierParameter;
 import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
+import static org.sonar.server.ws.WsParameterBuilder.createDefaultTemplateQualifierParameter;
 import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_ORGANIZATION;
 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_QUALIFIER;
@@ -81,7 +81,7 @@ public class SetDefaultTemplateAction implements PermissionsWsAction {
       .setHandler(this);
 
     createTemplateParameters(action);
-    createRootQualifierParameter(action, newQualifierParameterContext(i18n, resourceTypes))
+    createDefaultTemplateQualifierParameter(action, newQualifierParameterContext(i18n, resourceTypes))
       .setDefaultValue(Qualifiers.PROJECT);
   }
 
index 9db9df75b8b6c9ff2bf0aff0e263407f531a2885..2fa5a29ad941a237c29734bea1206a9d9a2eb91e 100644 (file)
@@ -40,6 +40,7 @@ import org.sonarqube.ws.client.project.SearchWsRequest;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Optional.ofNullable;
+import static org.sonar.api.resources.Qualifiers.APP;
 import static org.sonar.api.resources.Qualifiers.PROJECT;
 import static org.sonar.api.resources.Qualifiers.VIEW;
 import static org.sonar.core.util.Protobuf.setNullable;
@@ -84,7 +85,7 @@ public class SearchAction implements ProjectsWsAction {
 
     action.createParam(PARAM_QUALIFIERS)
       .setDescription("Comma-separated list of component qualifiers. Filter the results with the specified qualifiers")
-      .setPossibleValues(PROJECT, VIEW)
+      .setPossibleValues(PROJECT, VIEW, APP)
       .setDefaultValue(PROJECT);
     support.addOrganizationParam(action);
 
index 95fb26c20e3f9923df20c280ef9b8ee2b82e995f..709ae53305fca0a9e5009dd1e8a42fdc0f710964 100644 (file)
  */
 package org.sonar.server.project.ws;
 
-import com.google.common.collect.ImmutableSet;
-import java.util.Set;
 import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.resources.Scopes;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
@@ -49,8 +46,6 @@ import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
 
 public class UpdateVisibilityAction implements ProjectsWsAction {
-  private static final Set<String> ALLOWED_QUALIFIERS = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.VIEW);
-
   private final DbClient dbClient;
   private final ComponentFinder componentFinder;
   private final UserSession userSession;
@@ -68,19 +63,19 @@ public class UpdateVisibilityAction implements ProjectsWsAction {
 
   public void define(WebService.NewController context) {
     WebService.NewAction action = context.createAction(ProjectsWsParameters.ACTION_UPDATE_VISIBILITY)
-      .setDescription("Updates visibility of a project or a view.<br/>" +
-        "Requires 'Project administer' permission on the specified project or view")
+      .setDescription("Updates visibility of a project.<br>" +
+        "Requires 'Project administer' permission on the specified project")
       .setSince("6.4")
       .setPost(true)
       .setHandler(this);
 
     action.createParam(PARAM_PROJECT)
-      .setDescription("Project or view key")
+      .setDescription("Project key")
       .setExampleValue(KEY_PROJECT_EXAMPLE_001)
       .setRequired(true);
 
     action.createParam(PARAM_VISIBILITY)
-      .setDescription("new visibility of the project or view")
+      .setDescription("New visibility")
       .setPossibleValues(Visibility.getLabels())
       .setRequired(true);
   }
@@ -94,8 +89,7 @@ public class UpdateVisibilityAction implements ProjectsWsAction {
 
     try (DbSession dbSession = dbClient.openSession(false)) {
       ComponentDto component = componentFinder.getByKey(dbSession, projectKey);
-      checkRequest(isRoot(component), "Component must either be a project or a view");
-      checkRequest(!changeToPrivate || !Qualifiers.VIEW.equals(component.qualifier()), "Views can't be made private");
+      checkRequest(component.isRootProject() && Qualifiers.PROJECT.equals(component.qualifier()), "Component must be a project");
       userSession.checkComponentPermission(UserRole.ADMIN, component);
       checkRequest(noPendingTask(dbSession, component), "Component visibility can't be changed as long as it has background task(s) pending or in progress");
 
@@ -114,10 +108,6 @@ public class UpdateVisibilityAction implements ProjectsWsAction {
     }
   }
 
-  private static boolean isRoot(ComponentDto component) {
-    return Scopes.PROJECT.equals(component.scope()) && ALLOWED_QUALIFIERS.contains(component.qualifier());
-  }
-
   private boolean noPendingTask(DbSession dbSession, ComponentDto rootComponent) {
     return dbClient.ceQueueDao().selectByComponentUuid(dbSession, rootComponent.uuid()).isEmpty();
   }
index 51076887c2735482a2957f95bc7fa78e87388926..7766954c9920f0aeae397223c7618e6ff1edec33 100644 (file)
@@ -63,7 +63,7 @@ public class SettingValidations {
     };
   }
 
-  private static final Set<String> SUPPORTED_QUALIFIERS = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.VIEW, Qualifiers.MODULE, Qualifiers.SUBVIEW);
+  private static final Set<String> SUPPORTED_QUALIFIERS = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.VIEW, Qualifiers.APP, Qualifiers.MODULE, Qualifiers.SUBVIEW);
 
   public Consumer<SettingData> qualifier() {
     return data -> {
index 2f216ef4e4be6609ca3a23d8224605c6b89ab23f..e976aecd5e09c513835cd8e7e882954f839864d3 100644 (file)
@@ -82,7 +82,7 @@ public class ComponentAction implements NavigationWsAction {
   /**
    * The concept of "visibility" will only be configured for these qualifiers.
    */
-  private static final Set<String> QUALIFIERS_WITH_VISIBILITY = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.VIEW);
+  private static final Set<String> QUALIFIERS_WITH_VISIBILITY = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.VIEW, Qualifiers.APP);
 
   private final DbClient dbClient;
   private final PageRepository pageRepository;
@@ -248,7 +248,7 @@ public class ComponentAction implements NavigationWsAction {
   private void writeConfigPageAccess(JsonWriter json, boolean isProjectAdmin, ComponentDto component, OrganizationDto organization) {
     boolean isProject = Qualifiers.PROJECT.equals(component.qualifier());
     boolean showManualMeasures = isProjectAdmin && !Qualifiers.DIRECTORY.equals(component.qualifier());
-    boolean showBackgroundTasks = isProjectAdmin && (isProject || Qualifiers.VIEW.equals(component.qualifier()));
+    boolean showBackgroundTasks = isProjectAdmin && (isProject || Qualifiers.VIEW.equals(component.qualifier()) || Qualifiers.APP.equals(component.qualifier()));
     boolean isQualityProfileAdmin = userSession.hasPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, component.getOrganizationUuid());
     boolean isQualityGateAdmin = userSession.hasPermission(OrganizationPermission.ADMINISTER_QUALITY_GATES, component.getOrganizationUuid());
     boolean isOrganizationAdmin = userSession.hasPermission(OrganizationPermission.ADMINISTER, component.getOrganizationUuid());
index 30650111064273c3882a47fe73fcdb6ada4163f1..d1cae3abacf37e717657f525e78fbba3d13a38ab 100644 (file)
  */
 package org.sonar.server.ws;
 
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableSet;
 import java.util.Locale;
 import java.util.Set;
-import javax.annotation.Nullable;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
 import org.sonar.api.i18n.I18n;
 import org.sonar.api.resources.Qualifiers;
 import org.sonar.api.resources.ResourceType;
 import org.sonar.api.resources.ResourceTypes;
 import org.sonar.api.server.ws.WebService;
 
-import static com.google.common.base.Predicates.not;
-import static com.google.common.collect.FluentIterable.from;
-import static com.google.common.collect.Ordering.natural;
 import static java.lang.String.format;
 
 public class WsParameterBuilder {
   private static final String PARAM_QUALIFIER = "qualifier";
   private static final String PARAM_QUALIFIERS = "qualifiers";
-  private static final Set<String> DEPRECATED_QUALIFIERS = ImmutableSet.of(Qualifiers.LIBRARY);
 
   private WsParameterBuilder() {
     // static methods only
@@ -50,6 +45,12 @@ public class WsParameterBuilder {
       .setPossibleValues(getRootQualifiers(context.getResourceTypes()));
   }
 
+  public static WebService.NewParam createDefaultTemplateQualifierParameter(WebService.NewAction action, QualifierParameterContext context) {
+    return action.createParam(PARAM_QUALIFIER)
+      .setDescription("Project qualifier. Filter the results with the specified qualifier. Possible values are:" + buildDefaultTemplateQualifiersDescription(context))
+      .setPossibleValues(getDefaultTemplateQualifiers(context.getResourceTypes()));
+  }
+
   public static WebService.NewParam createQualifiersParameter(WebService.NewAction action, QualifierParameterContext context) {
     return action.createParam(PARAM_QUALIFIERS)
       .setDescription(
@@ -58,17 +59,26 @@ public class WsParameterBuilder {
   }
 
   private static Set<String> getRootQualifiers(ResourceTypes resourceTypes) {
-    return from(resourceTypes.getRoots())
-      .transform(ResourceType::getQualifier)
-      .filter(not(IsDeprecatedQualifier.INSTANCE))
-      .toSortedSet(natural());
+    return resourceTypes.getRoots().stream()
+      .map(ResourceType::getQualifier)
+      .collect(Collectors.toCollection(TreeSet::new));
+  }
+
+  private static Set<String> getDefaultTemplateQualifiers(ResourceTypes resourceTypes) {
+    return resourceTypes.getRoots().stream()
+      .map(ResourceType::getQualifier)
+      .filter(q -> !Qualifiers.APP.equals(q))
+      .collect(Collectors.toCollection(TreeSet::new));
   }
 
   private static Set<String> getAllQualifiers(ResourceTypes resourceTypes) {
-    return from(resourceTypes.getAll())
-      .transform(ResourceType::getQualifier)
-      .filter(not(IsDeprecatedQualifier.INSTANCE))
-      .toSortedSet(natural());
+    return resourceTypes.getAll().stream()
+      .map(ResourceType::getQualifier)
+      .collect(Collectors.toCollection(TreeSet::new));
+  }
+
+  private static String buildDefaultTemplateQualifiersDescription(QualifierParameterContext context) {
+    return buildQualifiersDescription(context, getDefaultTemplateQualifiers(context.getResourceTypes()));
   }
 
   private static String buildRootQualifiersDescription(QualifierParameterContext context) {
@@ -96,15 +106,6 @@ public class WsParameterBuilder {
     return context.getI18n().message(Locale.ENGLISH, qualifiersPropertyPrefix + qualifier, "no description available");
   }
 
-  private enum IsDeprecatedQualifier implements Predicate<String> {
-    INSTANCE;
-
-    @Override
-    public boolean apply(@Nullable String input) {
-      return DEPRECATED_QUALIFIERS.contains(input);
-    }
-  }
-
   public static class QualifierParameterContext {
     private final I18n i18n;
     private final ResourceTypes resourceTypes;
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/component/ws/components-example-suggestions.json b/server/sonar-server/src/main/resources/org/sonar/server/component/ws/components-example-suggestions.json
deleted file mode 100644 (file)
index 9bcb023..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-{
-  "results": [
-    {
-      "q": "VW",
-      "items": [],
-      "more": 0
-    },
-    {
-      "q": "SVW",
-      "items": [],
-      "more": 0
-    },
-    {
-      "q": "TRK",
-      "items": [
-        {
-          "key": "org.sonarsource:sonarqube",
-          "name": "SonarSource :: SonarQube",
-          "match": "<mark>Sonar</mark>Source :: <mark>Sonar</mark>Qube",
-          "organization": "default-organization",
-          "project": "",
-          "isRecentlyBrowsed": true,
-          "isFavorite": false
-        },
-        {
-          "key": "org.sonarsource:sonarlint",
-          "name": "SonarSource :: SonarLint",
-          "match": "<mark>Sonar</mark>Source :: <mark>Sonar</mark>Lint",
-          "organization": "default-organization",
-          "project": "",
-          "isRecentlyBrowsed": false,
-          "isFavorite": false
-        }
-      ],
-      "more": 0
-    },
-    {
-      "q": "BRC",
-      "items": [],
-      "more": 0
-    },
-    {
-      "q": "FIL",
-      "items": [],
-      "more": 0
-    },
-    {
-      "q": "UTS",
-      "items": [],
-      "more": 0
-    }
-  ],
-  "organizations": [
-    {
-      "key": "default-organization",
-      "name": "Default Organization"
-    }
-  ],
-  "projects": [
-  ]
-}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/component/ws/suggestions-example.json b/server/sonar-server/src/main/resources/org/sonar/server/component/ws/suggestions-example.json
new file mode 100644 (file)
index 0000000..3c7bbd4
--- /dev/null
@@ -0,0 +1,66 @@
+{
+  "results": [
+    {
+      "q": "VW",
+      "items": [],
+      "more": 0
+    },
+    {
+      "q": "SVW",
+      "items": [],
+      "more": 0
+    },
+    {
+      "q": "APP",
+      "items": [],
+      "more": 0
+    },
+    {
+      "q": "TRK",
+      "items": [
+        {
+          "key": "org.sonarsource:sonarqube",
+          "name": "SonarSource :: SonarQube",
+          "match": "<mark>Sonar</mark>Source :: <mark>Sonar</mark>Qube",
+          "organization": "default-organization",
+          "project": "",
+          "isRecentlyBrowsed": true,
+          "isFavorite": false
+        },
+        {
+          "key": "org.sonarsource:sonarlint",
+          "name": "SonarSource :: SonarLint",
+          "match": "<mark>Sonar</mark>Source :: <mark>Sonar</mark>Lint",
+          "organization": "default-organization",
+          "project": "",
+          "isRecentlyBrowsed": false,
+          "isFavorite": false
+        }
+      ],
+      "more": 0
+    },
+    {
+      "q": "BRC",
+      "items": [],
+      "more": 0
+    },
+    {
+      "q": "FIL",
+      "items": [],
+      "more": 0
+    },
+    {
+      "q": "UTS",
+      "items": [],
+      "more": 0
+    }
+  ],
+  "organizations": [
+    {
+      "key": "default-organization",
+      "name": "Default Organization"
+    }
+  ],
+  "projects": [
+  ]
+}
index 37718679766a9e443c365aa94235556b134520ae..b15d105343959d835855b0792f308236153ffd22 100644 (file)
@@ -94,6 +94,7 @@ public class ProjectDataLoaderTest {
     String[][] allScopesAndQualifierButProjectAndModule = {
       {Scopes.PROJECT, Qualifiers.VIEW},
       {Scopes.PROJECT, Qualifiers.SUBVIEW},
+      {Scopes.PROJECT, Qualifiers.APP},
       {Scopes.FILE, Qualifiers.PROJECT},
       {Scopes.DIRECTORY, Qualifiers.DIRECTORY},
       {Scopes.FILE, Qualifiers.UNIT_TEST_FILE},
index 07aa4ea77a5f1a2cb3f8ed786455051ddc4f9d97..4cca6f805ac746a25eff76413eca7bbc7beeb316 100644 (file)
@@ -47,12 +47,14 @@ import org.sonar.test.JsonAssert;
 import org.sonarqube.ws.MediaTypes;
 import org.sonarqube.ws.WsCe;
 import org.sonarqube.ws.WsCe.ActivityResponse;
+import org.sonarqube.ws.WsCe.Task;
 
 import static java.util.Arrays.asList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.sonar.api.utils.DateUtils.formatDate;
 import static org.sonar.api.utils.DateUtils.formatDateTime;
+import static org.sonar.db.component.ComponentTesting.newApplication;
 import static org.sonar.db.component.ComponentTesting.newView;
 import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_ID;
 import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_QUERY;
@@ -91,7 +93,7 @@ public class ActivityActionTest {
 
     assertThat(activityResponse.getTasksCount()).isEqualTo(2);
     // chronological order, from newest to oldest
-    WsCe.Task task = activityResponse.getTasks(0);
+    Task task = activityResponse.getTasks(0);
     assertThat(task.getOrganization()).isEqualTo(org2.getKey());
     assertThat(task.getId()).isEqualTo("T2");
     assertThat(task.getStatus()).isEqualTo(WsCe.TaskStatus.FAILED);
@@ -267,6 +269,19 @@ public class ActivityActionTest {
     assertThat(activityResponse.getTasksList()).extracting("id").containsOnly("T2");
   }
 
+  @Test
+  public void search_activity_returns_application() {
+    OrganizationDto organizationDto = dbTester.organizations().insert();
+    ComponentDto apacheApp = newApplication(organizationDto).setName("Apache App");
+    dbTester.components().insertViewAndSnapshot(apacheApp);
+    logInAsSystemAdministrator();
+    insertActivity("T2", apacheApp.uuid(), CeActivityDto.Status.SUCCESS);
+
+    ActivityResponse activityResponse = call(ws.newRequest().setParam(PARAM_COMPONENT_QUERY, "apac"));
+
+    assertThat(activityResponse.getTasksList()).extracting(Task::getId).containsOnly("T2");
+  }
+
   @Test
   public void search_task_id_in_queue_ignoring_other_parameters() throws IOException {
     logInAsSystemAdministrator();
index 46e6fb57617ce2ec677a270502ace88409d1575a..d5d95abdbfae5f10adcb414fcbb15534d8526327 100644 (file)
@@ -153,7 +153,25 @@ public class ComponentUpdaterTest {
     assertThat(loaded.getKey()).isEqualTo("view-key");
     assertThat(loaded.name()).isEqualTo("view-name");
     assertThat(loaded.qualifier()).isEqualTo("VW");
-    verify(projectIndexers).hasBeenCalled(loaded.uuid(), ProjectIndexer.Cause.PROJECT_CREATION);
+    assertThat(projectIndexers.hasBeenCalled(loaded.uuid(), ProjectIndexer.Cause.PROJECT_CREATION)).isTrue();
+  }
+
+  @Test
+  public void persist_and_index_when_creating_application() {
+    NewComponent view = NewComponent.newComponentBuilder()
+      .setKey("app-key")
+      .setName("app-name")
+      .setQualifier(APP)
+      .setOrganizationUuid(db.getDefaultOrganization().getUuid())
+      .build();
+
+    ComponentDto returned = underTest.create(db.getSession(), view, null);
+
+    ComponentDto loaded = db.getDbClient().componentDao().selectOrFailByUuid(db.getSession(), returned.uuid());
+    assertThat(loaded.getKey()).isEqualTo("app-key");
+    assertThat(loaded.name()).isEqualTo("app-name");
+    assertThat(loaded.qualifier()).isEqualTo("APP");
+    assertThat(projectIndexers.hasBeenCalled(loaded.uuid(), ProjectIndexer.Cause.PROJECT_CREATION)).isTrue();
   }
 
   @Test
@@ -171,7 +189,7 @@ public class ComponentUpdaterTest {
     assertThat(loaded.getKey()).isEqualTo("app-key");
     assertThat(loaded.name()).isEqualTo("app-name");
     assertThat(loaded.qualifier()).isEqualTo("APP");
-    verify(projectIndexers).hasBeenCalled(loaded.uuid(), ProjectIndexer.Cause.PROJECT_CREATION);
+    assertThat(projectIndexers.hasBeenCalled(loaded.uuid(), ProjectIndexer.Cause.PROJECT_CREATION)).isTrue();
   }
 
   @Test
index c0c6518f4ce540b67199bb209e5a3de45c35a965..b7caf99fd1a4a228f27f79015ac6fb8deaa3a8a4 100644 (file)
@@ -49,7 +49,6 @@ import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.TestResponse;
 import org.sonar.server.ws.WsActionTester;
-import org.sonar.test.JsonAssert;
 import org.sonarqube.ws.MediaTypes;
 import org.sonarqube.ws.WsComponents.SuggestionsWsResponse;
 import org.sonarqube.ws.WsComponents.SuggestionsWsResponse.Category;
@@ -68,6 +67,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.groups.Tuple.tuple;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.sonar.api.resources.Qualifiers.APP;
 import static org.sonar.api.resources.Qualifiers.FILE;
 import static org.sonar.api.resources.Qualifiers.MODULE;
 import static org.sonar.api.resources.Qualifiers.PROJECT;
@@ -81,6 +81,7 @@ import static org.sonar.server.component.ws.SuggestionsAction.PARAM_MORE;
 import static org.sonar.server.component.ws.SuggestionsAction.PARAM_QUERY;
 import static org.sonar.server.component.ws.SuggestionsAction.PARAM_RECENTLY_BROWSED;
 import static org.sonar.server.component.ws.SuggestionsAction.SHORT_INPUT_WARNING;
+import static org.sonar.test.JsonAssert.assertJson;
 
 public class SuggestionsActionTest {
   private static final String[] SUGGESTION_QUALIFIERS = Stream.of(SuggestionCategory.values())
@@ -152,7 +153,7 @@ public class SuggestionsActionTest {
       .setMediaType(MediaTypes.JSON)
       .execute();
 
-    JsonAssert.assertJson(ws.getDef().responseExampleAsString()).isSimilarTo(wsResponse.getInput());
+    assertJson(ws.getDef().responseExampleAsString()).isSimilarTo(wsResponse.getInput());
   }
 
   @Test
@@ -348,7 +349,7 @@ public class SuggestionsActionTest {
 
     assertThat(response.getResultsList())
       .extracting(Category::getQ, Category::getItemsCount)
-      .containsExactlyInAnyOrder(tuple("VW", 0), tuple("SVW", 0), tuple("TRK", 1), tuple("BRC", 0), tuple("FIL", 0), tuple("UTS", 0));
+      .containsExactlyInAnyOrder(tuple("VW", 0), tuple("APP", 0), tuple("SVW", 0), tuple("TRK", 1), tuple("BRC", 0), tuple("FIL", 0), tuple("UTS", 0));
   }
 
   @Test
@@ -564,13 +565,14 @@ public class SuggestionsActionTest {
 
     assertThat(response.getResultsList())
       .extracting(Category::getQ, Category::getItemsCount)
-      .containsExactlyInAnyOrder(tuple("VW", 0), tuple("SVW", 0), tuple("TRK", 1), tuple("BRC", 0), tuple("FIL", 0), tuple("UTS", 0));
+      .containsExactlyInAnyOrder(tuple("VW", 0), tuple("SVW", 0), tuple("APP", 0), tuple("TRK", 1), tuple("BRC", 0), tuple("FIL", 0), tuple("UTS", 0));
   }
 
   @Test
   public void should_only_provide_project_for_certain_qualifiers() throws Exception {
     String query = randomAlphabetic(10);
 
+    ComponentDto app = db.components().insertApplication(organization, v -> v.setName(query));
     ComponentDto view = db.components().insertView(organization, v -> v.setName(query));
     ComponentDto subView = db.components().insertComponent(ComponentTesting.newSubView(view).setName(query));
     ComponentDto project = db.components().insertPrivateProject(organization, p -> p.setName(query));
@@ -580,6 +582,7 @@ public class SuggestionsActionTest {
     componentIndexer.indexOnStartup(null);
     authorizationIndexerTester.allowOnlyAnyone(project);
     authorizationIndexerTester.allowOnlyAnyone(view);
+    authorizationIndexerTester.allowOnlyAnyone(app);
 
     SuggestionsWsResponse response = ws.newRequest()
       .setMethod("POST")
@@ -589,6 +592,7 @@ public class SuggestionsActionTest {
     assertThat(response.getResultsList())
       .extracting(Category::getQ, c -> c.getItemsList().stream().map(Suggestion::hasProject).findFirst().orElse(null))
       .containsExactlyInAnyOrder(
+        tuple(SuggestionCategory.APP.getName(), false),
         tuple(SuggestionCategory.VIEW.getName(), false),
         tuple(SuggestionCategory.SUBVIEW.getName(), false),
         tuple(SuggestionCategory.PROJECT.getName(), false),
@@ -689,7 +693,7 @@ public class SuggestionsActionTest {
 
   @Test
   public void show_more_results_filter_out_if_non_allowed_qualifiers() {
-    resourceTypes.setAllQualifiers(VIEW, SUBVIEW);
+    resourceTypes.setAllQualifiers(APP, VIEW, SUBVIEW);
 
     check_proposal_to_show_more_results(10, 0, 0L, SuggestionCategory.PROJECT, true);
   }
index 8b15aa45dc649d66632a8e1e071bc46afd329509..3e5302a2fdd27e929edbaf672a1022d0961a7925 100644 (file)
@@ -58,6 +58,7 @@ import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.tuple;
 import static org.sonar.api.utils.DateUtils.parseDateTime;
+import static org.sonar.db.component.ComponentTesting.newApplication;
 import static org.sonar.db.component.ComponentTesting.newDirectory;
 import static org.sonar.db.component.ComponentTesting.newFileDto;
 import static org.sonar.db.component.ComponentTesting.newModuleDto;
@@ -192,6 +193,24 @@ public class SearchActionTest {
     assertThat(measure.getValue()).isEqualTo("15.5");
   }
 
+
+  @Test
+  public void return_measures_on_application() throws Exception {
+    ComponentDto application = newApplication(db.getDefaultOrganization());
+    SnapshotDto viewSnapshot = db.components().insertProjectAndSnapshot(application);
+    MetricDto coverage = insertCoverageMetric();
+    dbClient.measureDao().insert(dbSession, newMeasureDto(coverage, application, viewSnapshot).setValue(15.5d));
+    db.commit();
+
+    SearchWsResponse result = call(singletonList(application.key()), singletonList("coverage"));
+
+    List<Measure> measures = result.getMeasuresList();
+    assertThat(measures).hasSize(1);
+    Measure measure = measures.get(0);
+    assertThat(measure.getMetric()).isEqualTo("coverage");
+    assertThat(measure.getValue()).isEqualTo("15.5");
+  }
+
   @Test
   public void return_measures_on_sub_view() throws Exception {
     ComponentDto view = newView(db.getDefaultOrganization());
@@ -332,7 +351,7 @@ public class SearchActionTest {
     insertComplexityMetric();
 
     expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("Only component of qualifiers [TRK, VW, SVW] are allowed");
+    expectedException.expectMessage("Only component of qualifiers [TRK, APP, VW, SVW] are allowed");
 
     call(singletonList(module.key()), singletonList("complexity"));
   }
@@ -345,7 +364,7 @@ public class SearchActionTest {
     insertComplexityMetric();
 
     expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("Only component of qualifiers [TRK, VW, SVW] are allowed");
+    expectedException.expectMessage("Only component of qualifiers [TRK, APP, VW, SVW] are allowed");
 
     call(singletonList(dir.key()), singletonList("complexity"));
   }
@@ -358,7 +377,7 @@ public class SearchActionTest {
     insertComplexityMetric();
 
     expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("Only component of qualifiers [TRK, VW, SVW] are allowed");
+    expectedException.expectMessage("Only component of qualifiers [TRK, APP, VW, SVW] are allowed");
 
     call(singletonList(file.key()), singletonList("complexity"));
   }
index 117e38fe39657497c73fb8d23a7f660fb0513bcb..920e4f78d3818fda807fbf339aa36ed89f357e3c 100644 (file)
@@ -229,11 +229,12 @@ public class DeleteActionTest {
     ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project));
     ComponentDto directory = db.components().insertComponent(ComponentTesting.newDirectory(module, "a/b"));
     ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(module, directory));
-    ComponentDto view = db.components().insertView(organization, (dto) -> {
-    });
+    ComponentDto view = db.components().insertView(organization);
     ComponentDto subview1 = db.components().insertComponent(ComponentTesting.newSubView(view, "v1", "ksv1"));
     ComponentDto subview2 = db.components().insertComponent(ComponentTesting.newSubView(subview1, "v2", "ksv2"));
+    ComponentDto application = db.components().insertApplication(organization);
     ComponentDto projectCopy = db.components().insertComponent(ComponentTesting.newProjectCopy("pc1", project, subview1));
+    ComponentDto projectCopyForApplication = db.components().insertComponent(ComponentTesting.newProjectCopy("pc2", project, application));
     logInAsAdministrator(organization);
 
     sendRequest(organization);
@@ -241,7 +242,7 @@ public class DeleteActionTest {
     verifyOrganizationDoesNotExist(organization);
     ArgumentCaptor<List<ComponentDto>> arg = (ArgumentCaptor<List<ComponentDto>>) ((ArgumentCaptor) ArgumentCaptor.forClass(List.class));
     verify(componentCleanerService).delete(any(DbSession.class), arg.capture());
-    assertThat(arg.getValue()).containsOnly(project, view);
+    assertThat(arg.getValue()).containsOnly(project, view, application);
   }
 
   @Test
index 407ad0eb6c5b3072c95db6d5e6409be3e4d1ebf7..601f4740a470229d7c670ec837ca30ad9fcdfaa6 100644 (file)
@@ -35,6 +35,7 @@ import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ComponentTesting;
+import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.permission.GroupPermissionDto;
 import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.UserDbTester;
@@ -43,6 +44,7 @@ import org.sonar.db.user.UserDto;
 import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.resources.Qualifiers.APP;
 import static org.sonar.api.resources.Qualifiers.PROJECT;
 import static org.sonar.api.resources.Qualifiers.VIEW;
 import static org.sonar.api.web.UserRole.ADMIN;
@@ -59,11 +61,13 @@ public class PermissionIndexerDaoTest {
   private ComponentDbTester componentDbTester = new ComponentDbTester(dbTester);
   private UserDbTester userDbTester = new UserDbTester(dbTester);
 
+  private OrganizationDto organization;
   private ComponentDto publicProject;
   private ComponentDto privateProject1;
   private ComponentDto privateProject2;
   private ComponentDto view1;
   private ComponentDto view2;
+  private ComponentDto application;
   private UserDto user1;
   private UserDto user2;
   private GroupDto group;
@@ -71,15 +75,17 @@ public class PermissionIndexerDaoTest {
   private PermissionIndexerDao underTest = new PermissionIndexerDao();
 
   @Before
-  public void setUp() throws Exception {
-    publicProject = componentDbTester.insertPublicProject();
-    privateProject1 = componentDbTester.insertPrivateProject();
-    privateProject2 = componentDbTester.insertPrivateProject();
-    view1 = componentDbTester.insertView();
-    view2 = componentDbTester.insertView();
+  public void setUp() {
+    organization = dbTester.organizations().insert();
+    publicProject = componentDbTester.insertPublicProject(organization);
+    privateProject1 = componentDbTester.insertPrivateProject(organization);
+    privateProject2 = componentDbTester.insertPrivateProject(organization);
+    view1 = componentDbTester.insertView(organization);
+    view2 = componentDbTester.insertView(organization);
+    application = componentDbTester.insertApplication(organization);
     user1 = userDbTester.insertUser();
     user2 = userDbTester.insertUser();
-    group = userDbTester.insertGroup();
+    group = userDbTester.insertGroup(organization);
   }
 
   @Test
@@ -87,7 +93,7 @@ public class PermissionIndexerDaoTest {
     insertTestDataForProjectsAndViews();
 
     Collection<PermissionIndexerDao.Dto> dtos = underTest.selectAll(dbClient, dbSession);
-    assertThat(dtos).hasSize(5);
+    assertThat(dtos).hasSize(6);
 
     PermissionIndexerDao.Dto publicProjectAuthorization = getByProjectUuid(publicProject.uuid(), dtos);
     isPublic(publicProjectAuthorization, PROJECT);
@@ -95,6 +101,9 @@ public class PermissionIndexerDaoTest {
     PermissionIndexerDao.Dto view1Authorization = getByProjectUuid(view1.uuid(), dtos);
     isPublic(view1Authorization, VIEW);
 
+    PermissionIndexerDao.Dto applicationAuthorization = getByProjectUuid(application.uuid(), dtos);
+    isPublic(applicationAuthorization, APP);
+
     PermissionIndexerDao.Dto privateProject1Authorization = getByProjectUuid(privateProject1.uuid(), dtos);
     assertThat(privateProject1Authorization.getGroupIds()).containsOnly(group.getId());
     assertThat(privateProject1Authorization.isAllowAnyone()).isFalse();
@@ -116,10 +125,10 @@ public class PermissionIndexerDaoTest {
     insertTestDataForProjectsAndViews();
 
     Map<String, PermissionIndexerDao.Dto> dtos = underTest
-      .selectByUuids(dbClient, dbSession, asList(publicProject.uuid(), privateProject1.uuid(), privateProject2.uuid(), view1.uuid(), view2.uuid()))
+      .selectByUuids(dbClient, dbSession, asList(publicProject.uuid(), privateProject1.uuid(), privateProject2.uuid(), view1.uuid(), view2.uuid(), application.uuid()))
       .stream()
       .collect(MoreCollectors.uniqueIndex(PermissionIndexerDao.Dto::getProjectUuid, Function.identity()));
-    assertThat(dtos).hasSize(5);
+    assertThat(dtos).hasSize(6);
 
     PermissionIndexerDao.Dto publicProjectAuthorization = dtos.get(publicProject.uuid());
     isPublic(publicProjectAuthorization, PROJECT);
@@ -127,6 +136,9 @@ public class PermissionIndexerDaoTest {
     PermissionIndexerDao.Dto view1Authorization = dtos.get(view1.uuid());
     isPublic(view1Authorization, VIEW);
 
+    PermissionIndexerDao.Dto applicationAuthorization = dtos.get(application.uuid());
+    isPublic(applicationAuthorization, APP);
+
     PermissionIndexerDao.Dto privateProject1Authorization = dtos.get(privateProject1.uuid());
     assertThat(privateProject1Authorization.getGroupIds()).containsOnly(group.getId());
     assertThat(privateProject1Authorization.isAllowAnyone()).isFalse();
@@ -155,7 +167,7 @@ public class PermissionIndexerDaoTest {
   public void select_by_projects_with_high_number_of_projects() throws Exception {
     List<String> projectUuids = new ArrayList<>();
     for (int i = 0; i < 350; i++) {
-      ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization(), Integer.toString(i));
+      ComponentDto project = ComponentTesting.newPrivateProjectDto(organization, Integer.toString(i));
       dbClient.componentDao().insert(dbSession, project);
       projectUuids.add(project.uuid());
       GroupPermissionDto dto = new GroupPermissionDto()
@@ -246,6 +258,7 @@ public class PermissionIndexerDaoTest {
     userDbTester.insertProjectPermissionOnUser(user1, USER, privateProject1);
     userDbTester.insertProjectPermissionOnUser(user1, USER, privateProject2);
     userDbTester.insertProjectPermissionOnUser(user1, ADMIN, view1);
+    userDbTester.insertProjectPermissionOnUser(user1, ADMIN, application);
 
     // user2 has USER access on privateProject1 only
     userDbTester.insertProjectPermissionOnUser(user2, USER, privateProject1);
@@ -255,5 +268,6 @@ public class PermissionIndexerDaoTest {
     userDbTester.insertProjectPermissionOnGroup(group, USER, privateProject1);
     userDbTester.insertProjectPermissionOnGroup(group, ADMIN, privateProject1);
     userDbTester.insertProjectPermissionOnGroup(group, ADMIN, view1);
+    userDbTester.insertProjectPermissionOnGroup(group, ADMIN, application);
   }
 }
index cbc6023290fe6abebc5acc4b3e309cefc3879d51..a4757a8719f8fe1bbdacd47b8a5f737505d84d95 100644 (file)
@@ -79,7 +79,7 @@ public abstract class BasePermissionWsTest<A extends PermissionsWsAction> {
   }
 
   protected ResourceTypesRule newRootResourceTypes() {
-    return new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW);
+    return new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW, Qualifiers.APP);
   }
 
   protected PermissionUpdater newPermissionUpdater() {
index 18387a307509d0393277f2effc7c49eb03938a41..b22c1c0449bb7fbd8a0cbb2e2ef119a26b34569b 100644 (file)
@@ -37,6 +37,7 @@ import org.sonar.server.permission.ws.BasePermissionWsTest;
 import org.sonar.server.ws.TestRequest;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.resources.Qualifiers.APP;
 import static org.sonar.api.resources.Qualifiers.PROJECT;
 import static org.sonar.api.resources.Qualifiers.VIEW;
 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_ORGANIZATION;
@@ -111,6 +112,20 @@ public class SetDefaultTemplateActionTest extends BasePermissionWsTest<SetDefaul
     assertDefaultTemplates(organization, projectDefaultTemplate.getUuid(), template.getUuid());
   }
 
+  @Test
+  public void fail_if_update_default_template_with_app_qualifier() throws Exception {
+    OrganizationDto organization = db.organizations().insert();
+    PermissionTemplateDto projectDefaultTemplate = db.permissionTemplates().insertTemplate(organization);
+    db.organizations().setDefaultTemplates(projectDefaultTemplate, null);
+    PermissionTemplateDto template = insertTemplate(organization);
+    loginAsAdmin(organization);
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Value of parameter 'qualifier' (APP) must be one of: [TRK, VW]");
+
+    newRequest(template.getUuid(), APP);
+  }
+
   @Test
   public void fail_if_anonymous() throws Exception {
     OrganizationDto organization = db.organizations().insert();
index 603873ebddb4d7d56eb199d9dc2da7f6071304b9..852f48c82aa664cc77f6c82b87c1978bb434f4bd 100644 (file)
@@ -237,7 +237,7 @@ public class SearchActionTest {
   public void fail_on_invalid_qualifier() throws Exception {
     userSession.addPermission(ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization());
     expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("Value of parameter 'qualifiers' (BRC) must be one of: [TRK, VW]");
+    expectedException.expectMessage("Value of parameter 'qualifiers' (BRC) must be one of: [TRK, VW, APP]");
 
     call(SearchWsRequest.builder().setQualifiers(singletonList("BRC")).build());
   }
@@ -267,7 +267,7 @@ public class SearchActionTest {
     WebService.Param qualifierParam = action.param("qualifiers");
     assertThat(qualifierParam.isRequired()).isFalse();
     assertThat(qualifierParam.description()).isEqualTo("Comma-separated list of component qualifiers. Filter the results with the specified qualifiers");
-    assertThat(qualifierParam.possibleValues()).containsOnly("TRK", "VW");
+    assertThat(qualifierParam.possibleValues()).containsOnly("TRK", "VW", "APP");
     assertThat(qualifierParam.defaultValue()).isEqualTo("TRK");
 
     WebService.Param pParam = action.param("p");
index 3854fb3c9268c6d362a49c7f58e8aa5f369b2674..dd6dd8d9fba39092d016bd014456ec8088de0c95 100644 (file)
@@ -66,6 +66,7 @@ import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
+import static org.sonar.db.component.ComponentTesting.newProjectCopy;
 import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto;
 
 public class UpdateVisibilityActionTest {
@@ -184,10 +185,10 @@ public class UpdateVisibilityActionTest {
     dbTester.components().insertComponents(module, dir, file);
     ComponentDto view = dbTester.components().insertView(organization);
     ComponentDto subView = ComponentTesting.newSubView(view);
-    ComponentDto projectCopy = ComponentTesting.newProjectCopy("foo", project, subView);
+    ComponentDto projectCopy = newProjectCopy("foo", project, subView);
     dbTester.components().insertComponents(subView, projectCopy);
 
-    Stream.of(module, dir, file, subView, projectCopy)
+    Stream.of(module, dir, file, view, subView, projectCopy)
       .forEach(nonRootComponent -> {
         request.setParam(PARAM_PROJECT, nonRootComponent.key())
           .setParam(PARAM_VISIBILITY, randomVisibility);
@@ -196,7 +197,7 @@ public class UpdateVisibilityActionTest {
           request.execute();
           fail("a BadRequestException should have been raised");
         } catch (BadRequestException e) {
-          assertThat(e.getMessage()).isEqualTo("Component must either be a project or a view");
+          assertThat(e.getMessage()).isEqualTo("Component must be a project");
         }
       });
   }
@@ -295,43 +296,6 @@ public class UpdateVisibilityActionTest {
     assertThat(isPrivateInDb(file)).isEqualTo(!initiallyPrivate);
   }
 
-  @Test
-  public void execute_has_no_effect_when_changing_a_view_to_public() {
-    OrganizationDto organization = dbTester.organizations().insert();
-    ComponentDto project = randomPublicOrPrivateProject();
-    ComponentDto view = dbTester.components().insertView(organization);
-    ComponentDto subView = ComponentTesting.newSubView(view);
-    ComponentDto projectCopy = ComponentTesting.newProjectCopy("foo", project, subView);
-    dbTester.components().insertComponents(subView, projectCopy);
-    userSessionRule.addProjectPermission(UserRole.ADMIN, view);
-
-    request.setParam(PARAM_PROJECT, view.key())
-      .setParam(PARAM_VISIBILITY, PUBLIC)
-      .execute();
-
-    assertThat(isPrivateInDb(view)).isEqualTo(false);
-    assertThat(isPrivateInDb(subView)).isEqualTo(false);
-    assertThat(isPrivateInDb(projectCopy)).isEqualTo(false);
-  }
-
-  @Test
-  public void execute_fails_with_BadRequestException_when_changing_a_view_to_private() {
-    OrganizationDto organization = dbTester.organizations().insert();
-    ComponentDto project = randomPublicOrPrivateProject();
-    ComponentDto view = dbTester.components().insertView(organization);
-    ComponentDto subView = ComponentTesting.newSubView(view);
-    ComponentDto projectCopy = ComponentTesting.newProjectCopy("foo", project, subView);
-    dbTester.components().insertComponents(subView, projectCopy);
-    userSessionRule.addProjectPermission(UserRole.ADMIN, view);
-    TestRequest request = this.request.setParam(PARAM_PROJECT, view.key())
-      .setParam(PARAM_VISIBILITY, PRIVATE);
-
-    expectedException.expect(BadRequestException.class);
-    expectedException.expectMessage("Views can't be made private");
-
-    request.execute();
-  }
-
   @Test
   public void execute_has_no_effect_if_specified_project_already_has_specified_visibility() {
     ComponentDto project = randomPublicOrPrivateProject();
@@ -420,22 +384,6 @@ public class UpdateVisibilityActionTest {
     verifyStillHasAllPermissions(project, user, group);
   }
 
-  @Test
-  public void execute_does_not_delete_permissions_USER_and_BROWSE_of_specified_view_when_making_it_public() {
-    OrganizationDto organization = dbTester.organizations().insert();
-    ComponentDto view = dbTester.components().insertView(organization);
-    UserDto user = dbTester.users().insertUser();
-    GroupDto group = dbTester.users().insertGroup(organization);
-    unsafeGiveAllPermissionsToRootComponent(view, user, group, organization);
-    userSessionRule.addProjectPermission(UserRole.ADMIN, view);
-
-    request.setParam(PARAM_PROJECT, view.key())
-      .setParam(PARAM_VISIBILITY, PUBLIC)
-      .execute();
-
-    verifyStillHasAllPermissions(view, user, group);
-  }
-
   @Test
   public void execute_updates_permission_of_specified_project_in_indexes_when_changing_visibility() {
     ComponentDto project = randomPublicOrPrivateProject();
@@ -462,19 +410,6 @@ public class UpdateVisibilityActionTest {
     assertThat(projectIndexers.hasBeenCalled(project.uuid())).isFalse();
   }
 
-  @Test
-  public void execute_does_not_update_permission_of_specified_view_in_indexes_when_making_it_public() {
-    OrganizationDto organization = dbTester.organizations().insert();
-    ComponentDto view = dbTester.components().insertView(organization);
-    userSessionRule.addProjectPermission(UserRole.ADMIN, view);
-
-    request.setParam(PARAM_PROJECT, view.key())
-      .setParam(PARAM_VISIBILITY, PUBLIC)
-      .execute();
-
-    assertThat(projectIndexers.hasBeenCalled(view.uuid())).isFalse();
-  }
-
   @Test
   public void execute_grants_USER_and_CODEVIEWER_permissions_to_any_user_with_at_least_one_permission_when_making_project_private() {
     OrganizationDto organization = dbTester.organizations().insert();