From: Jean-Baptiste Lievremont Date: Fri, 17 Apr 2015 14:32:23 +0000 (+0200) Subject: SONAR-6298 Add project count in qprofile search WS response X-Git-Tag: 5.2-RC1~2193 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=5f49af5dab1f5e76bbe1281855cf52cf369b6c95;p=sonarqube.git SONAR-6298 Add project count in qprofile search WS response --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileSearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileSearchAction.java index 9560c6b1422..8742cd7bb3b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileSearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileSearchAction.java @@ -28,6 +28,7 @@ import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService.NewAction; import org.sonar.api.utils.text.JsonWriter; +import org.sonar.core.qualityprofile.db.QualityProfileDao; import org.sonar.core.util.NonNullInputFunction; import org.sonar.server.qualityprofile.QProfile; import org.sonar.server.qualityprofile.QProfileLoader; @@ -36,7 +37,11 @@ import org.sonar.server.qualityprofile.QProfileLookup; import javax.annotation.CheckForNull; import javax.annotation.Nullable; -import java.util.*; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; public class QProfileSearchAction implements BaseQProfileWsAction { @@ -49,8 +54,11 @@ public class QProfileSearchAction implements BaseQProfileWsAction { private static final String FIELD_PARENT_KEY = "parentKey"; private static final String FIELD_PARENT_NAME = "parentName"; private static final String FIELD_ACTIVE_RULE_COUNT = "activeRuleCount"; + private static final String FIELD_PROJECT_COUNT = "projectCount"; + private static final Set ALL_FIELDS = ImmutableSet.of( - FIELD_KEY, FIELD_NAME, FIELD_LANGUAGE, FIELD_LANGUAGE_NAME, FIELD_IS_INHERITED, FIELD_PARENT_KEY, FIELD_PARENT_NAME, FIELD_IS_DEFAULT, FIELD_ACTIVE_RULE_COUNT); + FIELD_KEY, FIELD_NAME, FIELD_LANGUAGE, FIELD_LANGUAGE_NAME, FIELD_IS_INHERITED, FIELD_PARENT_KEY, FIELD_PARENT_NAME, FIELD_IS_DEFAULT, FIELD_ACTIVE_RULE_COUNT, + FIELD_PROJECT_COUNT); private static final String PARAM_LANGUAGE = FIELD_LANGUAGE; private static final String PARAM_FIELDS = "f"; @@ -62,10 +70,13 @@ public class QProfileSearchAction implements BaseQProfileWsAction { private final QProfileLoader profileLoader; - public QProfileSearchAction(Languages languages, QProfileLookup profileLookup, QProfileLoader profileLoader) { + private final QualityProfileDao qualityProfileDao; + + public QProfileSearchAction(Languages languages, QProfileLookup profileLookup, QProfileLoader profileLoader, QualityProfileDao qualityProfileDao) { this.languages = languages; this.profileLookup = profileLookup; this.profileLoader = profileLoader; + this.qualityProfileDao = qualityProfileDao; } @Override @@ -123,6 +134,7 @@ public class QProfileSearchAction implements BaseQProfileWsAction { } }); Map activeRuleCountByKey = profileLoader.countAllActiveRules(); + Map projectCountByKey = qualityProfileDao.countProjectsByProfileKey(); json.name("profiles") @@ -135,10 +147,15 @@ public class QProfileSearchAction implements BaseQProfileWsAction { String key = profile.key(); Long activeRuleCount = activeRuleCountByKey.containsKey(key) ? activeRuleCountByKey.get(key) : 0L; + Long projectCount = projectCountByKey.containsKey(key) ? projectCountByKey.get(key) : 0L; json.beginObject() .prop(FIELD_KEY, nullUnlessNeeded(FIELD_KEY, key, fields)) .prop(FIELD_NAME, nullUnlessNeeded(FIELD_NAME, profile.name(), fields)) .prop(FIELD_ACTIVE_RULE_COUNT, nullUnlessNeeded(FIELD_ACTIVE_RULE_COUNT, activeRuleCount, fields)); + + if (!profile.isDefault()) { + json.prop(FIELD_PROJECT_COUNT, nullUnlessNeeded(FIELD_PROJECT_COUNT, projectCount, fields)); + } writeLanguageFields(json, profile, fields); writeParentFields(json, profile, fields, profilesByKey); // Special case for booleans diff --git a/server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/example-search.json b/server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/example-search.json index 9c796636896..1a0a85588f6 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/example-search.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/example-search.json @@ -6,7 +6,8 @@ "language": "cs", "languageName": "C#", "isInherited": false, - "activeRuleCount": 37 + "activeRuleCount": 37, + "isDefault": true }, { "key": "my-bu-profile-java-34567", @@ -16,7 +17,9 @@ "isInherited": true, "parentKey": "my-company-profile-java-23456", "parentName": "My Company Profile", - "activeRuleCount": 72 + "activeRuleCount": 72, + "isDefault": false, + "projectCount": 13 }, { "key": "my-company-profile-java-23456", @@ -33,7 +36,8 @@ "language": "py", "languageName": "Python", "isInherited": false, - "activeRuleCount": 125 + "activeRuleCount": 125, + "isDefault": true } ] } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileSearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileSearchActionTest.java index 4d78c497a72..6b93a45b05a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileSearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileSearchActionTest.java @@ -31,6 +31,8 @@ import org.sonar.core.persistence.DbSession; import org.sonar.core.persistence.DbTester; import org.sonar.core.qualityprofile.db.QualityProfileDao; import org.sonar.core.qualityprofile.db.QualityProfileDto; +import org.sonar.server.component.ComponentTesting; +import org.sonar.server.component.db.ComponentDao; import org.sonar.server.db.DbClient; import org.sonar.server.language.LanguageTesting; import org.sonar.server.qualityprofile.QProfileLoader; @@ -74,7 +76,7 @@ public class QProfileSearchActionTest { mock(RuleActivationActions.class), mock(BulkRuleActivationActions.class), mock(ProjectAssociationActions.class), - new QProfileSearchAction(new Languages(xoo1, xoo2), new QProfileLookup(dbClient), profileLoader))); + new QProfileSearchAction(new Languages(xoo1, xoo2), new QProfileLookup(dbClient), profileLoader, qualityProfileDao))); } @After @@ -95,6 +97,11 @@ public class QProfileSearchActionTest { QualityProfileDto.createFor("my-sonar-way-xoo2-34567").setLanguage(xoo2.getKey()).setName("My Sonar way").setParentKee("sonar-way-xoo2-23456"), QualityProfileDto.createFor("sonar-way-other-666").setLanguage("other").setName("Sonar way").setDefault(true) ); + new ComponentDao(mock(System2.class)).insert(session, + ComponentTesting.newProjectDto("project-uuid1"), + ComponentTesting.newProjectDto("project-uuid2")); + qualityProfileDao.insertProjectProfileAssociation("project-uuid1", "sonar-way-xoo2-23456", session); + qualityProfileDao.insertProjectProfileAssociation("project-uuid2", "sonar-way-xoo2-23456", session); session.commit(); tester.newGetRequest("api/qualityprofiles", "search").execute().assertJson(this.getClass(), "search.json"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java index 592033e1a61..653bf535936 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java @@ -63,7 +63,7 @@ public class QProfilesWsTest { new QProfileCreateAction(null, null, null, languages, importers), new QProfileImportersAction(importers), new QProfileRestoreBuiltInAction(null), - new QProfileSearchAction(languages, null, null), + new QProfileSearchAction(languages, null, null, null), new QProfileSetDefaultAction(languages, null, null), new QProfileProjectsAction(null), new QProfileBackupAction(null, null, null, languages), @@ -121,7 +121,7 @@ public class QProfilesWsTest { assertThat(search.params()).hasSize(2); assertThat(search.param("language").possibleValues()).containsOnly(xoo1Key, xoo2Key); assertThat(search.param("f").possibleValues()) - .containsOnly("key", "name", "language", "languageName", "isInherited", "parentKey", "parentName", "isDefault", "activeRuleCount"); + .containsOnly("key", "name", "language", "languageName", "isInherited", "parentKey", "parentName", "isDefault", "activeRuleCount", "projectCount"); } @Test diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/QProfileSearchActionTest/search.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/QProfileSearchActionTest/search.json index b800f3a3bce..6c051e7ac96 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/QProfileSearchActionTest/search.json +++ b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/QProfileSearchActionTest/search.json @@ -18,7 +18,8 @@ "isDefault": false, "parentKey": "sonar-way-xoo2-23456", "parentName": "Sonar way", - "activeRuleCount": 33 + "activeRuleCount": 33, + "projectCount": 0 }, { "key": "sonar-way-xoo2-23456", @@ -27,7 +28,8 @@ "languageName": "Xoo2", "isInherited": false, "isDefault": false, - "activeRuleCount": 0 + "activeRuleCount": 0, + "projectCount": 2 } ] } \ No newline at end of file diff --git a/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDao.java b/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDao.java index 81b7ddbf24b..19af5b22d78 100644 --- a/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDao.java +++ b/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDao.java @@ -22,6 +22,7 @@ package org.sonar.core.qualityprofile.db; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import org.sonar.api.ServerComponent; import org.sonar.api.utils.System2; import org.sonar.core.component.ComponentDto; @@ -34,6 +35,7 @@ import javax.annotation.Nullable; import java.util.Date; import java.util.List; +import java.util.Map; public class QualityProfileDao implements ServerComponent, DaoComponent { @@ -47,7 +49,7 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { @CheckForNull public QualityProfileDto getByKey(DbSession session, String key) { - return session.getMapper(QualityProfileMapper.class).selectByKey(key); + return getMapper(session).selectByKey(key); } public QualityProfileDto getNonNullByKey(DbSession session, String key) { @@ -59,11 +61,11 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { } public List findAll(DbSession session) { - return session.getMapper(QualityProfileMapper.class).selectAll(); + return getMapper(session).selectAll(); } public void insert(DbSession session, QualityProfileDto profile, QualityProfileDto... otherProfiles) { - QualityProfileMapper mapper = session.getMapper(QualityProfileMapper.class); + QualityProfileMapper mapper = getMapper(session); doInsert(mapper, profile); for (QualityProfileDto other : otherProfiles) { doInsert(mapper, other); @@ -93,7 +95,7 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { } public void update(DbSession session, QualityProfileDto profile, QualityProfileDto... otherProfiles) { - QualityProfileMapper mapper = session.getMapper(QualityProfileMapper.class); + QualityProfileMapper mapper = getMapper(session); doUpdate(mapper, profile); for (QualityProfileDto otherProfile : otherProfiles) { doUpdate(mapper, otherProfile); @@ -121,7 +123,7 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { } public void delete(DbSession session, QualityProfileDto profile, QualityProfileDto... otherProfiles) { - QualityProfileMapper mapper = session.getMapper(QualityProfileMapper.class); + QualityProfileMapper mapper = getMapper(session); doDelete(mapper, profile); for (QualityProfileDto otherProfile : otherProfiles) { doDelete(mapper, otherProfile); @@ -138,7 +140,7 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { */ @Deprecated public void delete(int id, DbSession session) { - session.getMapper(QualityProfileMapper.class).delete(id); + getMapper(session).delete(id); } /** @@ -163,7 +165,7 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { public List findAll() { DbSession session = mybatis.openSession(false); try { - return session.getMapper(QualityProfileMapper.class).selectAll(); + return getMapper(session).selectAll(); } finally { MyBatis.closeQuietly(session); } @@ -171,7 +173,7 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { @CheckForNull public QualityProfileDto getDefaultProfile(String language, DbSession session) { - return session.getMapper(QualityProfileMapper.class).selectDefaultProfile(language); + return getMapper(session).selectDefaultProfile(language); } @CheckForNull @@ -188,7 +190,7 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { public QualityProfileDto getByProjectAndLanguage(long projectId, String language) { DbSession session = mybatis.openSession(false); try { - return session.getMapper(QualityProfileMapper.class).selectByProjectIdAndLanguage(projectId, language); + return getMapper(session).selectByProjectIdAndLanguage(projectId, language); } finally { MyBatis.closeQuietly(session); } @@ -196,13 +198,13 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { @CheckForNull public QualityProfileDto getByProjectAndLanguage(String projectKey, String language, DbSession session) { - return session.getMapper(QualityProfileMapper.class).selectByProjectAndLanguage(projectKey, language); + return getMapper(session).selectByProjectAndLanguage(projectKey, language); } public List findByLanguage(String language) { DbSession session = mybatis.openSession(false); try { - return session.getMapper(QualityProfileMapper.class).selectByLanguage(language); + return getMapper(session).selectByLanguage(language); } finally { MyBatis.closeQuietly(session); } @@ -215,7 +217,7 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { @Deprecated @CheckForNull public QualityProfileDto getById(int id, DbSession session) { - return session.getMapper(QualityProfileMapper.class).selectById(id); + return getMapper(session).selectById(id); } /** @@ -235,7 +237,7 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { @CheckForNull public QualityProfileDto getParent(String childKey, DbSession session) { - return session.getMapper(QualityProfileMapper.class).selectParent(childKey); + return getMapper(session).selectParent(childKey); } @CheckForNull @@ -250,7 +252,7 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { @CheckForNull public QualityProfileDto getParentById(int childId, DbSession session) { - return session.getMapper(QualityProfileMapper.class).selectParentById(childId); + return getMapper(session).selectParentById(childId); } @CheckForNull @@ -264,7 +266,7 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { } public List findChildren(DbSession session, String key) { - return session.getMapper(QualityProfileMapper.class).selectChildren(key); + return getMapper(session).selectChildren(key); } /** @@ -281,7 +283,7 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { @CheckForNull public QualityProfileDto getByNameAndLanguage(String name, String language, DbSession session) { - return session.getMapper(QualityProfileMapper.class).selectByNameAndLanguage(name, language); + return getMapper(session).selectByNameAndLanguage(name, language); } /** @@ -308,50 +310,68 @@ public class QualityProfileDao implements ServerComponent, DaoComponent { } public List selectProjects(String profileName, String language, DbSession session) { - return session.getMapper(QualityProfileMapper.class).selectProjects(profileName, language); + return getMapper(session).selectProjects(profileName, language); } public int countProjects(String profileName, String language) { DbSession session = mybatis.openSession(false); try { - return session.getMapper(QualityProfileMapper.class).countProjects(profileName, language); + return getMapper(session).countProjects(profileName, language); + } finally { + MyBatis.closeQuietly(session); + } + } + + public Map countProjectsByProfileKey() { + DbSession session = mybatis.openSession(false); + try { + Map countByKey = Maps.newHashMap(); + for (QualityProfileProjectCount count : getMapper(session).countProjectsByProfile()) { + countByKey.put(count.getProfileKey(), count.getProjectCount()); + } + return countByKey; } finally { MyBatis.closeQuietly(session); } } public void insertProjectProfileAssociation(String projectUuid, String profileKey, DbSession session) { - session.getMapper(QualityProfileMapper.class).insertProjectProfileAssociation(projectUuid, profileKey); + getMapper(session).insertProjectProfileAssociation(projectUuid, profileKey); } public void deleteProjectProfileAssociation(String projectUuid, String profileKey, DbSession session) { - session.getMapper(QualityProfileMapper.class).deleteProjectProfileAssociation(projectUuid, profileKey); + getMapper(session).deleteProjectProfileAssociation(projectUuid, profileKey); } public void updateProjectProfileAssociation(String projectUuid, String profileKey, DbSession session) { - session.getMapper(QualityProfileMapper.class).updateProjectProfileAssociation(projectUuid, profileKey); + getMapper(session).updateProjectProfileAssociation(projectUuid, profileKey); } public void deleteAllProjectProfileAssociation(String profileKey, DbSession session) { - session.getMapper(QualityProfileMapper.class).deleteAllProjectProfileAssociation(profileKey); + getMapper(session).deleteAllProjectProfileAssociation(profileKey); } public List selectSelectedProjects(String profileKey, @Nullable String query, DbSession session) { String nameQuery = sqlQueryString(query); - return session.getMapper(QualityProfileMapper.class).selectSelectedProjects(profileKey, nameQuery); + return getMapper(session).selectSelectedProjects(profileKey, nameQuery); } public List selectDeselectedProjects(String profileKey, @Nullable String query, DbSession session) { String nameQuery = sqlQueryString(query); - return session.getMapper(QualityProfileMapper.class).selectDeselectedProjects(profileKey, nameQuery); + return getMapper(session).selectDeselectedProjects(profileKey, nameQuery); } public List selectProjectAssociations(String profileKey, @Nullable String query, DbSession session) { String nameQuery = sqlQueryString(query); - return session.getMapper(QualityProfileMapper.class).selectProjectAssociations(profileKey, nameQuery); + return getMapper(session).selectProjectAssociations(profileKey, nameQuery); } private String sqlQueryString(String query) { return query == null ? "%" : "%" + query.toUpperCase() + "%"; } + + private QualityProfileMapper getMapper(DbSession session) { + return session.getMapper(QualityProfileMapper.class); + } + } diff --git a/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileMapper.java b/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileMapper.java index 940c9adce99..a54a4789283 100644 --- a/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileMapper.java +++ b/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileMapper.java @@ -67,6 +67,8 @@ public interface QualityProfileMapper { int countProjects(@Param("profileName") String profileName, @Param("language") String language); + List countProjectsByProfile(); + QualityProfileDto selectByProjectIdAndLanguage(@Param("projectId") Long projectId, @Param("language") String language); QualityProfileDto selectByProjectAndLanguage(@Param("projectKey") String projectKey, @Param("language") String language); diff --git a/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileProjectCount.java b/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileProjectCount.java new file mode 100644 index 00000000000..a18bd449c8f --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileProjectCount.java @@ -0,0 +1,43 @@ +/* + * 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.qualityprofile.db; + + +public class QualityProfileProjectCount { + + private String profileKey; + private Long projectCount; + + public String getProfileKey() { + return profileKey; + } + + public void setProfileKey(String profileKey) { + this.profileKey = profileKey; + } + + public Long getProjectCount() { + return projectCount; + } + + public void setProjectCount(Long projectCount) { + this.projectCount = projectCount; + } +} diff --git a/sonar-core/src/main/resources/org/sonar/core/qualityprofile/db/QualityProfileMapper.xml b/sonar-core/src/main/resources/org/sonar/core/qualityprofile/db/QualityProfileMapper.xml index 3221d9bbf3d..9356b4f26d1 100644 --- a/sonar-core/src/main/resources/org/sonar/core/qualityprofile/db/QualityProfileMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/qualityprofile/db/QualityProfileMapper.xml @@ -151,6 +151,15 @@ + +