import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.config.Configuration;
import org.sonar.api.rule.Severity;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.utils.System2;
RuleIndex ruleIndex = new RuleIndex(es.client(), System2.INSTANCE);
ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db, es.client());
QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
- RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, db, new TypeValidations(singletonList(new IntegerTypeValidation())), userSession);
+ RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, db, new TypeValidations(singletonList(new IntegerTypeValidation())),
+ userSession, mock(Configuration.class));
qProfileRules = new QProfileRulesImpl(db, ruleActivator, ruleIndex, activeRuleIndexer, qualityProfileChangeEventService);
comparison = new QProfileComparison(db);
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.config.Configuration;
import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class);
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation()));
- private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession);
+ private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession, mock(Configuration.class));
private QProfileTree qProfileTree = new QProfileTreeImpl(db.getDbClient(), ruleActivator, system2, activeRuleIndexer, mock(QualityProfileChangeEventService.class));
private QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, null, activeRuleIndexer, qualityProfileChangeEventService);
private QProfileResetImpl underTest = new QProfileResetImpl(db.getDbClient(), ruleActivator, activeRuleIndexer, mock(QualityProfileChangeEventService.class));
}
@Test
- public void inherited_rules_are_not_disabled() {
+ public void reset_whenRuleInherited_canBeDisabled() {
QProfileDto parentProfile = db.qualityProfiles().insert(p -> p.setLanguage(LANGUAGE));
QProfileDto childProfile = db.qualityProfiles().insert(p -> p.setLanguage(LANGUAGE));
qProfileTree.setParentAndCommit(db.getSession(), childProfile, parentProfile);
assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), childProfile))
.extracting(OrgActiveRuleDto::getRuleKey)
- .containsExactlyInAnyOrder(newRule.getKey(), existingRule.getKey());
+ .containsExactlyInAnyOrder(newRule.getKey());
verify(qualityProfileChangeEventService, times(2)).distributeRuleChangeEvent(any(), any(), eq(childProfile.getLanguage()));
}
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
+import org.mockito.Mockito;
import org.sonar.api.PropertyType;
+import org.sonar.api.config.Configuration;
import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.utils.System2;
+import org.sonar.core.config.CorePropertyDefinitions;
import org.sonar.db.DbTester;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.OrgActiveRuleDto;
import static org.sonar.api.rule.Severity.MINOR;
import static org.sonar.db.rule.RuleTesting.newCustomRule;
import static org.sonar.server.qualityprofile.ActiveRuleInheritance.INHERITED;
+import static org.sonar.server.qualityprofile.ActiveRuleInheritance.OVERRIDES;
public class QProfileRuleImplIT {
private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient());
private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation()));
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
+ private Configuration configuration = mock(Configuration.class);
- private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession);
+ private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession, configuration);
private QProfileRules underTest = new QProfileRulesImpl(db.getDbClient(), ruleActivator, ruleIndex, activeRuleIndexer, qualityProfileChangeEventService);
@Test
}
@Test
- public void activation_on_child_profile_is_propagated_to_descendants() {
+ public void activate_shouldPropagateActivationOnChildren() {
RuleDto rule = createRule();
QProfileDto parentProfile = createProfile(rule);
QProfileDto childProfile = createChildProfile(parentProfile);
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(childProfile.getLanguage()));
}
+ @Test
+ public void activate_whenChildProfileAlreadyActivatedRule_shouldNotStopPropagating() {
+ RuleDto rule = createRule();
+ QProfileDto parentProfile = createProfile(rule);
+ QProfileDto childProfile = createChildProfile(parentProfile);
+ QProfileDto childProfile2 = createChildProfile(childProfile);
+ QProfileDto childProfile3 = createChildProfile(childProfile2);
+
+ RuleActivation activation = RuleActivation.create(rule.getUuid(), MAJOR, emptyMap());
+
+ // Rule already active on childProfile2
+ List<ActiveRuleChange> changes = activate(childProfile2, activation);
+ assertThatRuleIsActivated(childProfile2, rule, changes, rule.getSeverityString(), null, emptyMap());
+ verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
+ deactivate(childProfile3, rule);
+ assertThatProfileHasNoActiveRules(childProfile3);
+
+ changes = activate(parentProfile, activation);
+ assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap());
+ assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
+ assertThatRuleIsUpdated(childProfile2, rule, rule.getSeverityString(), INHERITED, emptyMap());
+ assertThatRuleIsActivated(childProfile3, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
+ assertThat(changes).hasSize(4);
+ verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
+ }
+
+ @Test
+ public void activate_whenChildAlreadyActivatedRuleWithOverriddenValues_shouldNotOverrideValues() {
+ RuleDto rule = createRule();
+ QProfileDto parentProfile = createProfile(rule);
+ QProfileDto childProfile = createChildProfile(parentProfile);
+ QProfileDto childProfile2 = createChildProfile(childProfile);
+ QProfileDto childProfile3 = createChildProfile(childProfile2);
+
+ List<ActiveRuleChange> changes = activate(childProfile2, RuleActivation.create(rule.getUuid(), CRITICAL, emptyMap()));
+ assertThatRuleIsActivated(childProfile2, rule, changes, CRITICAL, null, emptyMap());
+ assertThatRuleIsActivated(childProfile3, rule, changes, CRITICAL, INHERITED, emptyMap());
+ verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
+
+ changes = activate(parentProfile, RuleActivation.create(rule.getUuid(), MAJOR, emptyMap()));
+ assertThatRuleIsActivated(parentProfile, rule, changes, MAJOR, null, emptyMap());
+ assertThatRuleIsActivated(childProfile, rule, changes, MAJOR, INHERITED, emptyMap());
+ assertThatRuleIsUpdated(childProfile2, rule, CRITICAL, OVERRIDES, emptyMap());
+ // childProfile3 is neither activated nor updated, it keeps its inherited value from childProfile2
+ assertThat(changes).hasSize(3);
+ verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
+ }
+
+ @Test
+ public void activate_whenParentHasRuleWithSameValues_shouldMarkInherited() {
+ RuleDto rule = createRule();
+ QProfileDto parentProfile = createProfile(rule);
+ QProfileDto childProfile = createChildProfile(parentProfile);
+
+ List<ActiveRuleChange> changes = activate(parentProfile, RuleActivation.create(rule.getUuid(), CRITICAL, emptyMap()));
+ assertThatRuleIsActivated(parentProfile, rule, changes, CRITICAL, null, emptyMap());
+ deactivate(childProfile, rule);
+ assertThatProfileHasNoActiveRules(childProfile);
+
+ changes = activate(childProfile, RuleActivation.create(rule.getUuid(), CRITICAL, emptyMap()));
+ assertThatRuleIsActivated(childProfile, rule, changes, CRITICAL, INHERITED, emptyMap());
+ assertThat(changes).hasSize(1);
+ }
+
+ @Test
+ public void activate_whenParentHasRuleWithDifferentValues_shouldMarkOverridden() {
+ RuleDto rule = createRule();
+ QProfileDto parentProfile = createProfile(rule);
+ QProfileDto childProfile = createChildProfile(parentProfile);
+
+ List<ActiveRuleChange> changes = activate(parentProfile, RuleActivation.create(rule.getUuid(), CRITICAL, emptyMap()));
+ assertThatRuleIsActivated(parentProfile, rule, changes, CRITICAL, null, emptyMap());
+ deactivate(childProfile, rule);
+ assertThatProfileHasNoActiveRules(childProfile);
+
+ changes = activate(childProfile, RuleActivation.create(rule.getUuid(), MAJOR, emptyMap()));
+ assertThatRuleIsActivated(childProfile, rule, changes, MAJOR, OVERRIDES, emptyMap());
+ assertThat(changes).hasSize(1);
+ }
+
@Test
public void update_on_child_profile_is_propagated_to_descendants() {
RuleDto rule = createRule();
assertThatProfileHasNoActiveRules(parentProfile);
assertThatRuleIsUpdated(childProfile, rule, MAJOR, null, of(param.getName(), "foo"));
- assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar"));
+ assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, OVERRIDES, of(param.getName(), "bar"));
assertThat(changes).hasSize(1);
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
}
assertThatProfileHasNoActiveRules(parentProfile);
assertThatRuleIsUpdated(childProfile, rule, BLOCKER, null, of(param.getName(), "baz"));
- assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar"));
+ assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, OVERRIDES, of(param.getName(), "bar"));
assertThat(changes).hasSize(1);
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
}
test.put(param.getName(), param.getDefaultValue());
assertThatRuleIsUpdated(parentProfile, rule, rule.getSeverityString(), null, test);
assertThatRuleIsUpdated(childProfile, rule, rule.getSeverityString(), INHERITED, of(param.getName(), param.getDefaultValue()));
- assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar"));
+ assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, OVERRIDES, of(param.getName(), "bar"));
assertThat(changes).hasSize(2);
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
}
@Test
- public void active_on_parent_a_rule_already_activated_on_child() {
+ public void activate_whenRuleAlreadyActiveOnChildWithDifferentValues_shouldMarkOverridden() {
RuleDto rule = createRule();
RuleParamDto param = db.rules().insertRuleParam(rule);
QProfileDto parentProfile = createProfile(rule);
List<ActiveRuleChange> changes = activate(childProfile, childActivation);
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
- RuleActivation parentActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar"));
+ RuleActivation parentActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "bar"));
changes = activate(parentProfile, parentActivation);
- assertThatRuleIsUpdated(parentProfile, rule, CRITICAL, null, of(param.getName(), "bar"));
- assertThatRuleIsUpdated(childProfile, rule, MAJOR, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "foo"));
+ assertThatRuleIsUpdated(parentProfile, rule, MAJOR, null, of(param.getName(), "bar"));
+ assertThatRuleIsUpdated(childProfile, rule, MAJOR, OVERRIDES, of(param.getName(), "foo"));
assertThat(changes).hasSize(2);
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
}
@Test
- public void do_not_mark_as_overridden_if_same_values_than_parent() {
+ public void activate_whenRuleAlreadyActiveOnChildWithSameValues_shouldMarkInherited() {
+ RuleDto rule = createRule();
+ RuleParamDto param = db.rules().insertRuleParam(rule);
+ QProfileDto parentProfile = createProfile(rule);
+ QProfileDto childProfile = createChildProfile(parentProfile);
+
+ RuleActivation childActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
+ List<ActiveRuleChange> changes = activate(childProfile, childActivation);
+ verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
+
+ RuleActivation parentActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
+ changes = activate(parentProfile, parentActivation);
+
+ assertThatRuleIsUpdated(parentProfile, rule, MAJOR, null, of(param.getName(), "foo"));
+ assertThatRuleIsUpdated(childProfile, rule, MAJOR, INHERITED, of(param.getName(), "foo"));
+ assertThat(changes).hasSize(2);
+ verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
+ }
+
+ @Test
+ public void activate_whenSettingValuesOnChildAndParentHasSameValues_shouldMarkInherited() {
RuleDto rule = createRule();
RuleParamDto param = db.rules().insertRuleParam(rule);
QProfileDto parentProfile = createProfile(rule);
}
@Test
- public void propagate_deactivation_on_children() {
+ public void activate_whenSettingValuesOnChildAndParentHasDifferentValues_shouldMarkOverridden() {
+ RuleDto rule = createRule();
+ RuleParamDto param = db.rules().insertRuleParam(rule);
+ QProfileDto parentProfile = createProfile(rule);
+ QProfileDto childProfile = createChildProfile(parentProfile);
+
+ RuleActivation parentActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
+ List<ActiveRuleChange> changes = activate(parentProfile, parentActivation);
+ verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
+
+ RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar"));
+ changes = activate(childProfile, overrideActivation);
+
+ assertThatRuleIsUpdated(childProfile, rule, CRITICAL, OVERRIDES, of(param.getName(), "bar"));
+ assertThat(changes).hasSize(1);
+ verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
+ }
+
+ @Test
+ public void deactivate_shouldPropagateDeactivationOnChildren() {
RuleDto rule = createRule();
QProfileDto parentProfile = createProfile(rule);
QProfileDto childProfile = createChildProfile(parentProfile);
}
@Test
- public void propagate_deactivation_on_children_even_when_overridden() {
+ public void deactivate_whenChildAlreadyDeactivatedRule_shouldNotStopPropagating() {
+ RuleDto rule = createRule();
+ QProfileDto parentProfile = createProfile(rule);
+ QProfileDto childProfile = createChildProfile(parentProfile);
+ QProfileDto childProfile2 = createChildProfile(childProfile);
+ QProfileDto childProfile3 = createChildProfile(childProfile2);
+
+ RuleActivation activation = RuleActivation.create(rule.getUuid());
+
+ // Rule active on parentProfile, childProfile1 and childProfile3 but not on childProfile2
+ List<ActiveRuleChange> changes = activate(parentProfile, activation);
+ assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap());
+ assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
+ assertThatRuleIsActivated(childProfile2, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
+ assertThatRuleIsActivated(childProfile3, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
+ verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
+ deactivate(childProfile2, rule);
+ changes = activate(childProfile3, activation);
+ assertThatProfileHasNoActiveRules(childProfile2);
+ assertThatRuleIsActivated(childProfile3, rule, changes, rule.getSeverityString(), null, emptyMap());
+
+ changes = deactivate(parentProfile, rule);
+ assertThatProfileHasNoActiveRules(parentProfile);
+ assertThatProfileHasNoActiveRules(childProfile);
+ assertThatProfileHasNoActiveRules(childProfile2);
+ assertThatProfileHasNoActiveRules(childProfile3);
+ assertThat(changes).hasSize(3);
+ verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
+ }
+
+ @Test
+ public void deactivate_whenChildOverridesRule_shouldPropagateDeactivation() {
RuleDto rule = createRule();
QProfileDto parentProfile = createProfile(rule);
QProfileDto childProfile = createChildProfile(parentProfile);
activation = RuleActivation.create(rule.getUuid(), CRITICAL, null);
changes = activate(childProfile, activation);
+ assertThatRuleIsUpdated(childProfile, rule, CRITICAL, OVERRIDES, emptyMap());
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
changes = deactivate(parentProfile, rule);
}
@Test
- public void cannot_deactivate_rule_inherited() {
+ public void deactivate_whenRuleInherited_canBeDeactivated() {
+ RuleDto rule = createRule();
+ QProfileDto parentProfile = createProfile(rule);
+ QProfileDto childProfile = createChildProfile(parentProfile);
+
+ RuleActivation activation = RuleActivation.create(rule.getUuid());
+ List<ActiveRuleChange> changes = activate(parentProfile, activation);
+ assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap());
+ assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
+
+ changes = deactivate(childProfile, rule);
+ assertThatProfileHasNoActiveRules(childProfile);
+ assertThat(changes).hasSize(1);
+ verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
+ }
+
+ @Test
+ public void deactivate_whenRuleInheritedAndPropertyDisabled_cannotBeDeactivated() {
+ Mockito.when(configuration.getBoolean(CorePropertyDefinitions.ALLOW_DISABLE_INHERITED_RULES)).thenReturn(Optional.of(false));
+
RuleDto rule = createRule();
QProfileDto parentProfile = createProfile(rule);
QProfileDto childProfile = createChildProfile(parentProfile);
RuleActivation childActivation = RuleActivation.create(rule.getUuid(), BLOCKER, null);
changes = activate(childProfile, childActivation);
- assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRuleInheritance.OVERRIDES, emptyMap());
+ assertThatRuleIsUpdated(childProfile, rule, BLOCKER, OVERRIDES, emptyMap());
assertThat(changes).hasSize(1);
RuleActivation resetActivation = RuleActivation.createReset(rule.getUuid());
RuleActivation childActivation = RuleActivation.create(rule.getUuid(), BLOCKER, null);
changes = activate(childProfile, childActivation);
- assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRuleInheritance.OVERRIDES, emptyMap());
+ assertThatRuleIsUpdated(childProfile, rule, BLOCKER, OVERRIDES, emptyMap());
assertThatRuleIsUpdated(grandChildProfile, rule, BLOCKER, INHERITED, emptyMap());
assertThat(changes).hasSize(2);
RuleActivation resetActivation = RuleActivation.createReset(rule.getUuid());
changes = activate(baseProfile, resetActivation);
assertThatRuleIsUpdated(baseProfile, rule, rule.getSeverityString(), null, emptyMap());
- assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRuleInheritance.OVERRIDES, emptyMap());
+ assertThatRuleIsUpdated(childProfile, rule, BLOCKER, OVERRIDES, emptyMap());
assertThatRuleIsUpdated(grandChildProfile, rule, BLOCKER, INHERITED, emptyMap());
assertThat(changes).hasSize(1);
}
@Test
- public void bulk_deactivation_ignores_errors() {
+ public void bulkDeactivateAndCommit_whenRuleInherited_canBeDeactivated() {
RuleDto rule = createRule();
QProfileDto parentProfile = createProfile(rule);
QProfileDto childProfile = createChildProfile(parentProfile);
- List<ActiveRuleChange> changes = activate(parentProfile, RuleActivation.create(rule.getUuid()));
+ activate(parentProfile, RuleActivation.create(rule.getUuid()));
assertThatRuleIsActivated(parentProfile, rule, null, rule.getSeverityString(), null, emptyMap());
assertThatRuleIsActivated(childProfile, rule, null, rule.getSeverityString(), INHERITED, emptyMap());
.setQProfile(childProfile);
BulkChangeResult bulkChangeResult = underTest.bulkDeactivateAndCommit(db.getSession(), childProfile, ruleQuery);
- assertThat(bulkChangeResult.countFailed()).isOne();
- assertThat(bulkChangeResult.countSucceeded()).isZero();
- assertThat(bulkChangeResult.getChanges()).isEmpty();
- assertThatRuleIsActivated(parentProfile, rule, null, rule.getSeverityString(), null, emptyMap());
- assertThatRuleIsActivated(childProfile, rule, null, rule.getSeverityString(), INHERITED, emptyMap());
+ assertThat(bulkChangeResult.countFailed()).isZero();
+ assertThat(bulkChangeResult.countSucceeded()).isOne();
+ assertThat(bulkChangeResult.getChanges()).hasSize(1);
+ assertThatProfileHasNoActiveRules(childProfile);
}
@Test
import java.util.Collections;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.config.Configuration;
import org.sonar.api.rule.Severity;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
private RuleIndex ruleIndex = new RuleIndex(es.client(), System2.INSTANCE);
private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client());
private RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, db.getDbClient(), new TypeValidations(singletonList(new IntegerTypeValidation())),
- userSession);
+ userSession, mock(Configuration.class));
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
private QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, ruleIndex, activeRuleIndexer, qualityProfileChangeEventService);
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.config.Configuration;
import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client());
private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation()));
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
- private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession);
+ private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession, mock(Configuration.class));
private QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, null, activeRuleIndexer, qualityProfileChangeEventService);
private QProfileTree underTest = new QProfileTreeImpl(db.getDbClient(), ruleActivator, System2.INSTANCE, activeRuleIndexer, mock(QualityProfileChangeEventService.class));
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
+import org.sonar.api.config.Configuration;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RulePriority;
private ServerRuleFinder ruleFinder = new DefaultRuleFinder(dbClient, mock(RuleDescriptionFormatter.class));
private BuiltInQProfileInsert builtInQProfileInsert = new BuiltInQProfileInsertImpl(dbClient, ruleFinder, system2, UuidFactoryFast.getInstance(),
typeValidations, activeRuleIndexer);
- private RuleActivator ruleActivator = new RuleActivator(system2, dbClient, typeValidations, userSessionRule);
+ private RuleActivator ruleActivator = new RuleActivator(system2, dbClient, typeValidations, userSessionRule, mock(Configuration.class));
private QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, mock(RuleIndex.class), activeRuleIndexer, qualityProfileChangeEventService);
private BuiltInQProfileUpdate builtInQProfileUpdate = new BuiltInQProfileUpdateImpl(dbClient, ruleActivator, activeRuleIndexer, qualityProfileChangeEventService);
private BuiltInQualityProfilesUpdateListener builtInQualityProfilesNotification = mock(BuiltInQualityProfilesUpdateListener.class);
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.config.Configuration;
import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.NewBuiltInQualityProfile;
import org.sonar.api.utils.System2;
-import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleKey;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.sonar.api.rules.RulePriority.BLOCKER;
import static org.sonar.api.rules.RulePriority.CRITICAL;
import static org.sonar.api.rules.RulePriority.MAJOR;
private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class);
private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation()));
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
- private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession);
+ private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession, mock(Configuration.class));
private BuiltInQProfileUpdateImpl underTest = new BuiltInQProfileUpdateImpl(db.getDbClient(), ruleActivator, activeRuleIndexer,
qualityProfileChangeEventService);
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
}
- @Test
- public void do_not_load_descendants_if_no_changes() {
- RuleDto rule = db.rules().insert(r -> r.setLanguage("xoo"));
-
- QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
- QProfileDto childProfile = createChildProfile(profile);
-
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile(profile.getName(), profile.getLanguage());
- newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
- newQp.done();
-
- // first run
- BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(profile.getLanguage(), profile.getName()), rule);
- List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(profile));
- assertThat(changes).hasSize(2).extracting(ActiveRuleChange::getType).containsOnly(ActiveRuleChange.Type.ACTIVATED);
- verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
-
- // second run, without any input changes
- RuleActivator ruleActivatorWithoutDescendants = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession) {
- @Override
- DescendantProfilesSupplier createDescendantProfilesSupplier(DbSession dbSession) {
- return (profiles, ruleIds) -> {
- throw new IllegalStateException("BOOM - descendants should not be loaded");
- };
- }
- };
- changes = new BuiltInQProfileUpdateImpl(db.getDbClient(), ruleActivatorWithoutDescendants, activeRuleIndexer, qualityProfileChangeEventService)
- .update(db.getSession(), builtIn, RulesProfileDto.from(profile));
- assertThat(changes).isEmpty();
- verifyNoMoreInteractions(qualityProfileChangeEventService);
- }
-
@Test
public void propagate_deactivation_to_descendant_profiles() {
RuleDto rule = db.rules().insert(r -> r.setLanguage("xoo"));
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.config.Configuration;
import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
private final TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation()));
private final QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
- private final RuleActivator underTest = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession);
+ private final RuleActivator underTest = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession, mock(Configuration.class));
@Test
public void reset_overridden_active_rule() {
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.config.Configuration;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
ruleIndexer = new RuleIndexer(esClient, dbClient);
activeRuleIndexer = new ActiveRuleIndexer(dbClient, esClient);
TypeValidations typeValidations = new TypeValidations(Collections.emptyList());
- RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, dbClient, typeValidations, userSession);
+ RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, dbClient, typeValidations, userSession, mock(Configuration.class));
qProfileTree = new QProfileTreeImpl(dbClient, ruleActivator, System2.INSTANCE, activeRuleIndexer, mock(QualityProfileChangeEventService.class));
ChangeParentAction underTest = new ChangeParentAction(
dbClient,
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.config.Configuration;
import org.sonar.api.profiles.ProfileImporter;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.rules.RulePriority;
private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(dbClient, es.client());
private ProfileImporter[] profileImporters = createImporters();
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
- private RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, dbClient, null, userSession);
+ private RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, dbClient, null, userSession, mock(Configuration.class));
private QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, ruleIndex, activeRuleIndexer, qualityProfileChangeEventService);
private QProfileExporters qProfileExporters = new QProfileExporters(dbClient, null, qProfileRules, profileImporters);
import java.util.Date;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.config.Configuration;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
private RuleIndex ruleIndex = new RuleIndex(esClient, System2.INSTANCE);
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
- private RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, dbClient, new TypeValidations(new ArrayList<>()), userSession);
+ private RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, dbClient, new TypeValidations(new ArrayList<>()), userSession, mock(Configuration.class));
private QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, ruleIndex, activeRuleIndexer, qualityProfileChangeEventService);
private QProfileTree qProfileTree = new QProfileTreeImpl(dbClient, ruleActivator, System2.INSTANCE, activeRuleIndexer, mock(QualityProfileChangeEventService.class));
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.config.Configuration;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
private final ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(dbClient, es.client());
private final TypeValidations typeValidations = new TypeValidations(emptyList());
private final QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
- private final RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, dbClient, typeValidations, userSessionRule);
+ private final RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, dbClient, typeValidations, userSessionRule, mock(Configuration.class));
private final QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, ruleIndex, activeRuleIndexer, qualityProfileChangeEventService);
private final QProfileWsSupport qProfileWsSupport = new QProfileWsSupport(dbClient, userSessionRule);
private final RuleQueryFactory ruleQueryFactory = new RuleQueryFactory(dbClient);
import javax.annotation.Nullable;
import org.junit.Before;
import org.junit.Test;
+import org.sonar.api.config.Configuration;
import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.issue.impact.Severity;
import org.sonar.api.issue.impact.SoftwareQuality;
private final SearchAction underTest = new SearchAction(ruleIndex, activeRuleCompleter, ruleQueryFactory, db.getDbClient(), ruleMapper,
new RuleWsSupport(db.getDbClient(), userSession));
private final TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation()));
- private final RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, db.getDbClient(), typeValidations, userSession);
+ private final RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, db.getDbClient(), typeValidations, userSession,
+ mock(Configuration.class));
private final QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, ruleIndex, activeRuleIndexer,
qualityProfileChangeEventService);
private final WsActionTester ws = new WsActionTester(underTest);
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
import org.sonar.api.server.ServerSide;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
checkArgument(!profile.isBuiltIn(), "Operation forbidden for built-in Quality Profile '%s'", profile.getKee());
BulkChangeResult result = new BulkChangeResult();
- Set<String> rulesToBeDeactivated = new HashSet<>();
// Keep reference to all the activated rules before backup restore
- for (ActiveRuleDto activeRuleDto : db.activeRuleDao().selectByProfile(dbSession, profile)) {
- if (activeRuleDto.getInheritance() == null) {
- // inherited rules can't be deactivated
- rulesToBeDeactivated.add(activeRuleDto.getRuleUuid());
- }
- }
+ Set<String> rulesToBeDeactivated = db.activeRuleDao().selectByProfile(dbSession, profile).stream()
+ .map(ActiveRuleDto::getRuleUuid)
+ .collect(Collectors.toSet());
Set<String> ruleUuids = new HashSet<>(rulesToBeDeactivated.size() + activations.size());
ruleUuids.addAll(rulesToBeDeactivated);
activations.forEach(a -> ruleUuids.add(a.getRuleUuid()));
try {
changes.addAll(activator.deactivate(dbSession, context, ruleUuid, false));
} catch (BadRequestException e) {
- // ignore, probably a rule inherited from parent that can't be deactivated
+ // ignore, could be a removed rule
}
}
qualityProfileChangeEventService.distributeRuleChangeEvent(List.of(profile), changes, profile.getLanguage());
private void register(Collection<ActiveRuleDto> activeRules, Collection<ActiveRuleParamDto> activeRuleParams) {
ListMultimap<String, ActiveRuleParamDto> paramsByActiveRuleUuid = activeRuleParams.stream().collect(index(ActiveRuleParamDto::getActiveRuleUuid));
for (ActiveRuleDto activeRule : activeRules) {
- ActiveRuleWrapper wrapper = new ActiveRuleWrapper(activeRule, paramsByActiveRuleUuid.get(activeRule.getUuid()));
- this.activeRulesByKey.put(activeRule.getKey(), wrapper);
+ register(activeRule, paramsByActiveRuleUuid.get(activeRule.getUuid()));
}
}
+ void register(ActiveRuleDto activeRule, Collection<ActiveRuleParamDto> activeRuleParams) {
+ ActiveRuleWrapper wrapper = new ActiveRuleWrapper(activeRule, activeRuleParams);
+ this.activeRulesByKey.put(activeRule.getKey(), wrapper);
+ }
+
long getDate() {
return date;
}
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
+import org.sonar.api.config.Configuration;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.server.ServerSide;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.utils.System2;
+import org.sonar.core.config.CorePropertyDefinitions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.qualityprofile.ActiveRuleDao;
private final DbClient db;
private final TypeValidations typeValidations;
private final UserSession userSession;
+ private final Configuration configuration;
- public RuleActivator(System2 system2, DbClient db, TypeValidations typeValidations, UserSession userSession) {
+ public RuleActivator(System2 system2, DbClient db, TypeValidations typeValidations, UserSession userSession, Configuration configuration) {
this.system2 = system2;
this.db = db;
this.typeValidations = typeValidations;
this.userSession = userSession;
+ this.configuration = configuration;
}
-
public List<ActiveRuleChange> activate(DbSession dbSession, Collection<RuleActivation> activations, RuleActivationContext context) {
return activations.stream().map(a -> activate(dbSession, a, context))
.flatMap(List::stream)
checkRequest(RuleStatus.REMOVED != rule.getStatus(), "Rule was removed: %s", rule.getKey());
checkRequest(!rule.isTemplate(), "Rule template can't be activated on a Quality profile: %s", rule.getKey());
checkRequest(context.getRulesProfile().getLanguage().equals(rule.getLanguage()),
- "%s rule %s cannot be activated on %s profile %s", rule.getLanguage(), rule.getKey(), context.getRulesProfile().getLanguage(), context.getRulesProfile().getName());
+ "%s rule %s cannot be activated on %s profile %s", rule.getLanguage(), rule.getKey(), context.getRulesProfile().getLanguage(),
+ context.getRulesProfile().getName());
List<ActiveRuleChange> changes = new ArrayList<>();
- ActiveRuleChange change;
- boolean stopCascading = false;
+ ActiveRuleChange change = null;
ActiveRuleWrapper activeRule = context.getActiveRule();
ActiveRuleKey activeRuleKey = ActiveRuleKey.of(context.getRulesProfile(), rule.getKey());
change = handleNewRuleActivation(activation, context, rule, activeRuleKey);
} else {
// already activated
- if (context.isCascading() && activeRule.get().doesOverride()) {
- // propagating to descendants, but child profile already overrides rule -> stop propagation
- return changes;
- }
- change = new ActiveRuleChange(ActiveRuleChange.Type.UPDATED, activeRuleKey, rule);
- stopCascading = handleUpdatedRuleActivation(activation, context, change, stopCascading, activeRule);
- if (isSame(change, activeRule)) {
- change = null;
- stopCascading = true;
+ // No change if propagating to descendants, but child profile already overrides rule
+ if (!context.isCascading() || !activeRule.get().doesOverride()) {
+ change = new ActiveRuleChange(ActiveRuleChange.Type.UPDATED, activeRuleKey, rule);
+ handleUpdatedRuleActivation(activation, context, change, activeRule);
+
+ if (isSame(change, activeRule) || (context.isCascading() && activeRule.get().getInheritance() != null && !isSameAsParent(change, context))) {
+ // The rule config hasn't changed; or the rule is being propagated but the parent has a different config,
+ // which means the rule was overridden by a profile in the inheritance chain
+ change = null;
+ }
}
}
updateProfileDates(dbSession, context);
}
- if (!stopCascading) {
- changes.addAll(propagateActivationToDescendants(dbSession, activation, context));
- }
+ changes.addAll(propagateActivationToDescendants(dbSession, activation, context));
return changes;
}
- private boolean handleUpdatedRuleActivation(RuleActivation activation, RuleActivationContext context, ActiveRuleChange change,
- boolean stopCascading, ActiveRuleWrapper activeRule) {
+ private void handleUpdatedRuleActivation(RuleActivation activation, RuleActivationContext context, ActiveRuleChange change,
+ ActiveRuleWrapper activeRule) {
if (context.isCascading() && activeRule.get().getInheritance() == null) {
- // activate on child, then on parent -> mark child as overriding parent
- change.setInheritance(ActiveRuleInheritance.OVERRIDES);
+ // The rule is being propagated, but it was activated directly on this profile before
change.setSeverity(activeRule.get().getSeverityString());
for (ActiveRuleParamDto activeParam : activeRule.getParams()) {
change.setParameter(activeParam.getKey(), activeParam.getValue());
}
- stopCascading = true;
+ change.setInheritance(isSameAsParent(change, context) ? ActiveRuleInheritance.INHERITED : ActiveRuleInheritance.OVERRIDES);
} else {
applySeverityAndParamToChange(activation, context, change);
if (!context.isCascading() && context.getParentActiveRule() != null) {
change.setInheritance(isSameAsParent(change, context) ? ActiveRuleInheritance.INHERITED : ActiveRuleInheritance.OVERRIDES);
}
}
- return stopCascading;
}
private ActiveRuleChange handleNewRuleActivation(RuleActivation activation, RuleActivationContext context, RuleDto rule, ActiveRuleKey activeRuleKey) {
ActiveRuleChange change = new ActiveRuleChange(ActiveRuleChange.Type.ACTIVATED, activeRuleKey, rule);
applySeverityAndParamToChange(activation, context, change);
- if (context.isCascading() || isSameAsParent(change, context)) {
- change.setInheritance(ActiveRuleInheritance.INHERITED);
+ if (context.isCascading() || context.getParentActiveRule() != null) {
+ change.setInheritance(isSameAsParent(change, context) ? ActiveRuleInheritance.INHERITED : ActiveRuleInheritance.OVERRIDES);
}
return change;
}
activeRule.setUpdatedAt(system2.now());
activeRule.setCreatedAt(system2.now());
dao.insert(dbSession, activeRule);
+ List<ActiveRuleParamDto> params = new ArrayList<>();
for (Map.Entry<String, String> param : change.getParameters().entrySet()) {
if (param.getValue() != null) {
ActiveRuleParamDto paramDto = ActiveRuleParamDto.createFor(rule.getParam(param.getKey()));
paramDto.setValue(param.getValue());
+ params.add(paramDto);
dao.insertParam(dbSession, activeRule, paramDto);
}
}
+ context.register(activeRule, params);
return activeRule;
}
private List<ActiveRuleChange> doDeactivate(DbSession dbSession, RuleActivationContext context, boolean force) {
List<ActiveRuleChange> changes = new ArrayList<>();
ActiveRuleWrapper activeRule = context.getActiveRule();
- if (activeRule == null) {
- return changes;
- }
+ if (activeRule != null) {
+ checkRequest(force || context.isCascading() || activeRule.get().getInheritance() == null || isAllowDisableInheritedRules(),
+ "Cannot deactivate inherited rule '%s'", context.getRule().get().getKey());
- ActiveRuleChange change;
- checkRequest(force || context.isCascading() || activeRule.get().getInheritance() == null, "Cannot deactivate inherited rule '%s'", context.getRule().get().getKey());
- change = new ActiveRuleChange(ActiveRuleChange.Type.DEACTIVATED, activeRule.get(), context.getRule().get());
- changes.add(change);
- persist(change, context, dbSession);
+ ActiveRuleChange change = new ActiveRuleChange(ActiveRuleChange.Type.DEACTIVATED, activeRule.get(), context.getRule().get());
+ changes.add(change);
+ persist(change, context, dbSession);
+ }
// get all inherited profiles (they are not built-in by design)
context.getChildProfiles().forEach(child -> {
return changes;
}
+ private boolean isAllowDisableInheritedRules() {
+ return configuration.getBoolean(CorePropertyDefinitions.ALLOW_DISABLE_INHERITED_RULES).orElse(true);
+ }
+
@CheckForNull
private String validateParam(RuleParamDto ruleParam, @Nullable String value) {
if (value != null) {
return true;
}
- /**
- * True if trying to override an inherited rule but with exactly the same values
- */
private static boolean isSameAsParent(ActiveRuleChange change, RuleActivationContext context) {
ActiveRuleWrapper parentActiveRule = context.getParentActiveRule();
if (parentActiveRule == null) {
package org.sonar.server.qualityprofile.ws;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
"</ul>")
.setHandler(this)
.setPost(true)
- .setSince("4.4");
+ .setSince("4.4")
+ .setChangelog(new Change("10.3", "Inherited rules can be deactivated (if the global admin setting is enabled)"));
deactivate.createParam(PARAM_KEY)
.setDescription("Quality Profile key. Can be obtained through <code>api/qualityprofiles/search</code>")
.setPost(true)
.setSince("4.4")
.setChangelog(
+ new Change("10.3", "Inherited rules can be deactivated (if the global admin setting is enabled)"),
new Change("10.2", format("Parameters '%s', '%s', and '%s' are now deprecated.", PARAM_SEVERITIES, PARAM_ACTIVE_SEVERITIES, PARAM_TYPES)),
new Change("10.0", "Parameter 'sansTop25' is deprecated"))
.setHandler(this);