import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.ActiveRuleCountQuery;
import org.sonar.db.qualityprofile.QProfileDto;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.rule.index.RuleIndex;
+import org.sonar.server.rule.index.RuleQuery;
import org.sonarqube.ws.QualityProfiles.ShowWsResponse;
import org.sonarqube.ws.QualityProfiles.ShowWsResponse.CompareToSonarWay;
import org.sonarqube.ws.QualityProfiles.ShowWsResponse.QualityProfile;
private final DbClient dbClient;
private final QProfileWsSupport qProfileWsSupport;
private final Languages languages;
+ private final RuleIndex ruleIndex;
- public ShowAction(DbClient dbClient, QProfileWsSupport qProfileWsSupport, Languages languages) {
+ public ShowAction(DbClient dbClient, QProfileWsSupport qProfileWsSupport, Languages languages, RuleIndex ruleIndex) {
this.dbClient = dbClient;
this.qProfileWsSupport = qProfileWsSupport;
this.languages = languages;
+ this.ruleIndex = ruleIndex;
}
@Override
return null;
}
+ long missingRuleCount = ruleIndex.search(
+ new RuleQuery().setQProfile(profile).setActivation(false).setCompareToQProfile(sonarWay),
+ new SearchOptions().setLimit(1))
+ .getTotal();
+
return CompareToSonarWay.newBuilder()
.setProfile(sonarWay.getKee())
.setProfileName(sonarWay.getName())
+ .setMissingRuleCount(missingRuleCount)
.build();
}
package org.sonar.server.rule.index;
import com.google.common.base.Joiner;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RuleType;
+import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.server.es.EsClient;
import org.sonar.server.es.StickyFacetBuilder;
import static com.google.common.base.Preconditions.checkArgument;
+import static java.lang.Boolean.FALSE;
+import static java.lang.Boolean.TRUE;
import static java.util.Optional.ofNullable;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
public static final String FACET_TYPES = "types";
public static final String FACET_OLD_DEFAULT = "true";
- public static final List<String> ALL_STATUSES_EXCEPT_REMOVED = ImmutableList.copyOf(
- Collections2.filter(
- Collections2.transform(Arrays.asList(RuleStatus.values()), RuleStatus::toString),
- input -> !RuleStatus.REMOVED.toString().equals(input)));
+ public static final List<String> ALL_STATUSES_EXCEPT_REMOVED = Arrays.stream(RuleStatus.values())
+ .filter(status -> !RuleStatus.REMOVED.equals(status))
+ .map(RuleStatus::toString)
+ .collect(MoreCollectors.toList());
+
private static final String AGGREGATION_NAME = "_ref";
private static final String AGGREGATION_NAME_FOR_TAGS = "tagsAggregation";
private final EsClient client;
if (query.getActivation() != null && profile != null) {
// ActiveRule Filter (profile and inheritance)
- BoolQueryBuilder childrenFilter = boolQuery();
- addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_PROFILE_UUID, profile.getRulesProfileUuid());
- addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance());
- addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_SEVERITY, query.getActiveSeverities());
+ BoolQueryBuilder activeRuleFilter = boolQuery();
+ addTermFilter(activeRuleFilter, FIELD_ACTIVE_RULE_PROFILE_UUID, profile.getRulesProfileUuid());
+ addTermFilter(activeRuleFilter, FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance());
+ addTermFilter(activeRuleFilter, FIELD_ACTIVE_RULE_SEVERITY, query.getActiveSeverities());
// ChildQuery
QueryBuilder childQuery;
- if (childrenFilter.hasClauses()) {
- childQuery = childrenFilter;
+ if (activeRuleFilter.hasClauses()) {
+ childQuery = activeRuleFilter;
} else {
childQuery = matchAllQuery();
}
- if (Boolean.TRUE.equals(query.getActivation())) {
+ if (TRUE.equals(query.getActivation())) {
filters.put("activation",
QueryBuilders.hasChildQuery(INDEX_TYPE_ACTIVE_RULE.getType(),
childQuery));
- } else if (Boolean.FALSE.equals(query.getActivation())) {
+ } else if (FALSE.equals(query.getActivation())) {
filters.put("activation",
boolQuery().mustNot(
QueryBuilders.hasChildQuery(INDEX_TYPE_ACTIVE_RULE.getType(),
childQuery)));
}
+ QProfileDto compareToQProfile = query.getCompareToQProfile();
+ if (compareToQProfile != null) {
+ filters.put("comparison",
+ QueryBuilders.hasChildQuery(INDEX_TYPE_ACTIVE_RULE.getType(),
+ boolQuery().must(QueryBuilders.termQuery(FIELD_ACTIVE_RULE_PROFILE_UUID, compareToQProfile.getRulesProfileUuid()))));
+ }
}
return filters;
private Collection<RuleType> types;
private Boolean activation;
private QProfileDto profile;
+ private QProfileDto compareToQProfile;
private Collection<String> inheritance;
private Collection<String> activeSeverities;
private String templateKey;
this.organization = o;
return this;
}
+
+ @CheckForNull
+ public QProfileDto getCompareToQProfile() {
+ return compareToQProfile;
+ }
+
+ public RuleQuery setCompareToQProfile(@Nullable QProfileDto compareToQProfile) {
+ this.compareToQProfile = compareToQProfile;
+ return this;
+ }
}
"projectCount": 7,
"rulesUpdatedAt": "2016-12-22T19:10:03+0100",
"lastUsed": "2016-12-01T19:10:03+0100"
- },
- "compareToSonarWay": {
- "profile": "iU5OvuD2FLz",
- "profileName": "Sonar way",
- "missingRuleCount": 4
}
}
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.config.MapSettings;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.DateUtils;
import org.sonar.db.DbTester;
import org.sonar.db.qualityprofile.QProfileDto;
+import org.sonar.db.rule.RuleDefinitionDto;
+import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
+import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
+import org.sonar.server.qualityprofile.index.ActiveRuleIteratorFactory;
+import org.sonar.server.rule.index.RuleIndex;
+import org.sonar.server.rule.index.RuleIndexDefinition;
+import org.sonar.server.rule.index.RuleIndexer;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
private static Language XOO2 = newLanguage("xoo2");
private static Languages LANGUAGES = new Languages(XOO1, XOO2);
+ @Rule
+ public EsTester es = new EsTester(new RuleIndexDefinition(new MapSettings()));
@Rule
public DbTester db = DbTester.create();
@Rule
@Rule
public ExpectedException expectedException = ExpectedException.none();
+ private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient());
+ private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client(), new ActiveRuleIteratorFactory(db.getDbClient()));
+ private RuleIndex ruleIndex = new RuleIndex(es.client());
+
private WsActionTester ws = new WsActionTester(
- new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession, TestDefaultOrganizationProvider.from(db)), LANGUAGES));
+ new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession, TestDefaultOrganizationProvider.from(db)), LANGUAGES, ruleIndex));
@Test
public void test_definition() {
public void compare_to_sonar_way_profile() {
QProfileDto sonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(true).setName("Sonar way").setLanguage(XOO1.getKey()));
QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
+ RuleDefinitionDto commonRule = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
+ RuleDefinitionDto sonarWayRule1 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
+ RuleDefinitionDto sonarWayRule2 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
+ RuleDefinitionDto profileRule1 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
+ RuleDefinitionDto profileRule2 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
+ RuleDefinitionDto profileRule3 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
+ db.qualityProfiles().activateRule(profile, commonRule);
+ db.qualityProfiles().activateRule(profile, profileRule1);
+ db.qualityProfiles().activateRule(profile, profileRule2);
+ db.qualityProfiles().activateRule(profile, profileRule3);
+ db.qualityProfiles().activateRule(sonarWayProfile, commonRule);
+ db.qualityProfiles().activateRule(sonarWayProfile, sonarWayRule1);
+ db.qualityProfiles().activateRule(sonarWayProfile, sonarWayRule2);
+ ruleIndexer.indexOnStartup(ruleIndexer.getIndexTypes());
+ activeRuleIndexer.indexOnStartup(activeRuleIndexer.getIndexTypes());
+
+ CompareToSonarWay result = call(ws.newRequest()
+ .setParam(PARAM_PROFILE, profile.getKee())
+ .setParam(PARAM_COMPARE_TO_SONAR_WAY, "true"))
+ .getCompareToSonarWay();
+
+ assertThat(result)
+ .extracting(CompareToSonarWay::getProfile, CompareToSonarWay::getProfileName, CompareToSonarWay::getMissingRuleCount)
+ .containsExactly(sonarWayProfile.getKee(), sonarWayProfile.getName(), 2L);
+ }
+
+ @Test
+ public void compare_to_sonar_way_profile_when_same_active_rules() {
+ QProfileDto sonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(true).setName("Sonar way").setLanguage(XOO1.getKey()));
+ QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
+ RuleDefinitionDto commonRule = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
+ db.qualityProfiles().activateRule(profile, commonRule);
+ db.qualityProfiles().activateRule(sonarWayProfile, commonRule);
+ ruleIndexer.indexOnStartup(ruleIndexer.getIndexTypes());
+ activeRuleIndexer.indexOnStartup(activeRuleIndexer.getIndexTypes());
CompareToSonarWay result = call(ws.newRequest()
.setParam(PARAM_PROFILE, profile.getKee())
.getCompareToSonarWay();
assertThat(result)
- .extracting(CompareToSonarWay::getProfile, CompareToSonarWay::getProfileName)
- .containsExactly(sonarWayProfile.getKee(), sonarWayProfile.getName());
+ .extracting(CompareToSonarWay::getProfile, CompareToSonarWay::getProfileName, CompareToSonarWay::getMissingRuleCount)
+ .containsExactly(sonarWayProfile.getKee(), sonarWayProfile.getName(), 0L);
}
@Test
public void no_comparison_when_sonar_way_does_not_exist() {
- QProfileDto anotherSonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(true).setName("Another Sonar way").setLanguage(XOO1.getKey()));
+ QProfileDto anotherSonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(),
+ p -> p.setIsBuiltIn(true).setName("Another Sonar way").setLanguage(XOO1.getKey()));
QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
ShowWsResponse result = call(ws.newRequest()
CompareToSonarWay result = call(ws.newRequest()
.setParam(PARAM_PROFILE, profile.getKee())
.setParam(PARAM_COMPARE_TO_SONAR_WAY, "true"))
- .getCompareToSonarWay();
+ .getCompareToSonarWay();
assertThat(result)
.extracting(CompareToSonarWay::getProfile, CompareToSonarWay::getProfileName)
CompareToSonarWay result = call(ws.newRequest()
.setParam(PARAM_PROFILE, profile.getKee())
.setParam(PARAM_COMPARE_TO_SONAR_WAY, "true"))
- .getCompareToSonarWay();
+ .getCompareToSonarWay();
assertThat(result)
.extracting(CompareToSonarWay::getProfile, CompareToSonarWay::getProfileName)
.mapToObj(i -> db.components().insertPrivateProject())
.forEach(project -> db.qualityProfiles().associateWithProject(project, profile));
- ws = new WsActionTester(new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession, TestDefaultOrganizationProvider.from(db)), new Languages(cs)));
+ ws = new WsActionTester(
+ new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession, TestDefaultOrganizationProvider.from(db)), new Languages(cs), ruleIndex));
String result = ws.newRequest().setParam(PARAM_PROFILE, profile.getKee()).execute().getInput();
- assertJson(result).ignoreFields("rulesUpdatedAt", "lastUsed", "userUpdatedAt", "compareToSonarWay").isSimilarTo(ws.getDef().responseExampleAsString());
+ assertJson(result).ignoreFields("rulesUpdatedAt", "lastUsed", "userUpdatedAt").isSimilarTo(ws.getDef().responseExampleAsString());
}
private ShowWsResponse call(TestRequest request) {
assertThat(underTest.search(query, new SearchOptions()).getIds()).hasSize(2);
}
+ @Test
+ public void compare_to_another_profile() {
+ String xoo = "xoo";
+ QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(xoo));
+ QProfileDto anotherProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(xoo));
+ RuleDefinitionDto commonRule = db.rules().insertRule(r -> r.setLanguage(xoo)).getDefinition();
+ RuleDefinitionDto profileRule1 = db.rules().insertRule(r -> r.setLanguage(xoo)).getDefinition();
+ RuleDefinitionDto profileRule2 = db.rules().insertRule(r -> r.setLanguage(xoo)).getDefinition();
+ RuleDefinitionDto profileRule3 = db.rules().insertRule(r -> r.setLanguage(xoo)).getDefinition();
+ RuleDefinitionDto anotherProfileRule1 = db.rules().insertRule(r -> r.setLanguage(xoo)).getDefinition();
+ RuleDefinitionDto anotherProfileRule2 = db.rules().insertRule(r -> r.setLanguage(xoo)).getDefinition();
+ db.qualityProfiles().activateRule(profile, commonRule);
+ db.qualityProfiles().activateRule(profile, profileRule1);
+ db.qualityProfiles().activateRule(profile, profileRule2);
+ db.qualityProfiles().activateRule(profile, profileRule3);
+ db.qualityProfiles().activateRule(anotherProfile, commonRule);
+ db.qualityProfiles().activateRule(anotherProfile, anotherProfileRule1);
+ db.qualityProfiles().activateRule(anotherProfile, anotherProfileRule2);
+ index();
+
+ verifySearch(newRuleQuery().setActivation(false).setQProfile(profile).setCompareToQProfile(anotherProfile), anotherProfileRule1, anotherProfileRule2);
+ verifySearch(newRuleQuery().setActivation(true).setQProfile(profile).setCompareToQProfile(anotherProfile), commonRule);
+ verifySearch(newRuleQuery().setActivation(true).setQProfile(profile).setCompareToQProfile(profile), commonRule, profileRule1, profileRule2, profileRule3);
+ verifySearch(newRuleQuery().setActivation(false).setQProfile(profile).setCompareToQProfile(profile));
+ }
+
@SafeVarargs
private final RuleDefinitionDto createRule(Consumer<RuleDefinitionDto>... consumers) {
return db.rules().insert(consumers);