// batch
extensions.add(ProfileSensor.class);
+ extensions.add(ProfileEventsSensor.class);
extensions.add(ProjectLinksSensor.class);
extensions.add(AsynchronousMeasuresSensor.class);
extensions.add(UnitTestDecorator.class);
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.plugins.core.sensors;
+
+import org.sonar.api.batch.*;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.resources.Project;
+
+import java.util.List;
+
+public class ProfileEventsSensor implements Sensor {
+
+ private final RulesProfile profile;
+ private final TimeMachine timeMachine;
+
+ public ProfileEventsSensor(RulesProfile profile, TimeMachine timeMachine) {
+ this.profile = profile;
+ this.timeMachine = timeMachine;
+ }
+
+ public boolean shouldExecuteOnProject(Project project) {
+ return true;
+ }
+
+ public void analyse(Project project, SensorContext context) {
+ if (profile == null) {
+ return;
+ }
+ String currentProfile = profile.getName();
+ int currentProfileId = profile.getId();
+ int currentProfileVersion = profile.getVersion();
+
+ int pastProfileId = getPreviousMeasureValue(project, CoreMetrics.PROFILE, -1);
+ int pastProfileVersion = getPreviousMeasureValue(project, CoreMetrics.PROFILE, 1);
+
+ if (pastProfileId != currentProfileId) {
+ // A different profile is used for this project
+ context.createEvent(project, currentProfile + " V" + currentProfileVersion,
+ "A different quality profile was used", Event.CATEGORY_PROFILE, null);
+ } else if (pastProfileVersion != currentProfileVersion) {
+ // Same profile but new version
+ context.createEvent(project, currentProfile + " V" + currentProfileVersion,
+ "A new version of the quality profile was used", Event.CATEGORY_PROFILE, null);
+ }
+ }
+
+ private int getPreviousMeasureValue(Project project, Metric metric, int defaultValue) {
+ TimeMachineQuery query = new TimeMachineQuery(project)
+ .setOnlyLastAnalysis(true)
+ .setMetrics(metric);
+ List<Measure> measures = timeMachine.getMeasures(query);
+ if (measures.isEmpty()) {
+ return defaultValue;
+ }
+ return measures.get(0).getIntValue();
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName();
+ }
+}
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
+import org.sonar.api.database.DatabaseSession;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
import org.sonar.api.profiles.RulesProfile;
public class ProfileSensor implements Sensor {
- private RulesProfile profile;
+ private final RulesProfile profile;
+ private final DatabaseSession session;
- public ProfileSensor(RulesProfile profile) {
+ public ProfileSensor(RulesProfile profile, DatabaseSession session) {
this.profile = profile;
+ this.session = session;
}
public boolean shouldExecuteOnProject(Project project) {
public void analyse(Project project, SensorContext context) {
if (profile != null) {
Measure measure = new Measure(CoreMetrics.PROFILE, profile.getName());
+ Measure measureVersion = new Measure(CoreMetrics.PROFILE_VERSION, Integer.valueOf(profile.getVersion()).doubleValue());
if (profile.getId() != null) {
measure.setValue(profile.getId().doubleValue());
+
+ profile.setUsed(true);
+ session.merge(profile);
}
context.saveMeasure(measure);
+ context.saveMeasure(measureVersion);
}
}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.plugins.core.sensors;
+
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.batch.Event;
+import org.sonar.api.batch.SensorContext;
+import org.sonar.api.batch.TimeMachine;
+import org.sonar.api.batch.TimeMachineQuery;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
+
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+
+public class ProfileEventsSensorTest {
+
+ private Project project;
+ private SensorContext context;
+
+ @Before
+ public void prepare() {
+ project = mock(Project.class);
+ context = mock(SensorContext.class);
+ }
+
+ @Test
+ public void shouldDoNothingIfNoProfile() throws ParseException {
+ ProfileEventsSensor sensor = new ProfileEventsSensor(null, null);
+
+ sensor.analyse(project, context);
+
+ verify(context, never()).createEvent((Resource) anyObject(), anyString(), anyString(), anyString(), (Date) anyObject());
+ }
+
+ @Test
+ public void shouldDoNothingIfNoProfileChange() throws ParseException {
+ RulesProfile profile = mockProfile(1);
+ TimeMachine timeMachine = mockTM(project, 22.0, 1.0); // Same profile, same version
+ ProfileEventsSensor sensor = new ProfileEventsSensor(profile, timeMachine);
+
+ sensor.analyse(project, context);
+
+ verify(context, never()).createEvent((Resource) anyObject(), anyString(), anyString(), anyString(), (Date) anyObject());
+ }
+
+ @Test
+ public void shouldCreateEventIfProfileChange() throws ParseException {
+ RulesProfile profile = mockProfile(1);
+ TimeMachine timeMachine = mockTM(project, 21.0, 1.0); // Different profile
+ ProfileEventsSensor sensor = new ProfileEventsSensor(profile, timeMachine);
+
+ sensor.analyse(project, context);
+
+ verify(context).createEvent(same(project), eq("Profile V1"), eq("A different quality profile was used"),
+ same(Event.CATEGORY_PROFILE), (Date) anyObject());
+ }
+
+ @Test
+ public void shouldCreateEventIfProfileVersionChange() throws ParseException {
+ RulesProfile profile = mockProfile(2);
+ TimeMachine timeMachine = mockTM(project, 22.0, 1.0); // Same profile, different version
+ ProfileEventsSensor sensor = new ProfileEventsSensor(profile, timeMachine);
+
+ sensor.analyse(project, context);
+
+ verify(context).createEvent(same(project), eq("Profile V2"), eq("A new version of the quality profile was used"),
+ same(Event.CATEGORY_PROFILE), (Date) anyObject());
+ }
+
+ @Test
+ public void shouldCreateEventIfFirstAnalysis() throws ParseException {
+ RulesProfile profile = mockProfile(2);
+ TimeMachine timeMachine = mockTM(project, null, null);
+ ProfileEventsSensor sensor = new ProfileEventsSensor(profile, timeMachine);
+
+ sensor.analyse(project, context);
+
+ verify(context).createEvent(same(project), eq("Profile V2"), eq("A different quality profile was used"),
+ same(Event.CATEGORY_PROFILE), (Date) anyObject());
+ }
+
+ @Test
+ public void shouldNotCreateEventIfFirstProfileVersionAndStillV1() throws ParseException {
+ RulesProfile profile = mockProfile(1);
+ TimeMachine timeMachine = mockTMWithNullVersion(project, 22.0);
+ ProfileEventsSensor sensor = new ProfileEventsSensor(profile, timeMachine);
+
+ sensor.analyse(project, context);
+
+ verify(context, never()).createEvent((Resource) anyObject(), anyString(), anyString(), anyString(), (Date) anyObject());
+ }
+
+ @Test
+ public void shouldCreateEventIfFirstProfileVersionAndMoreThanV1() throws ParseException {
+ RulesProfile profile = mockProfile(2);
+ TimeMachine timeMachine = mockTMWithNullVersion(project, 22.0);
+ ProfileEventsSensor sensor = new ProfileEventsSensor(profile, timeMachine);
+
+ sensor.analyse(project, context);
+
+ verify(context).createEvent(same(project), eq("Profile V2"), eq("A new version of the quality profile was used"),
+ same(Event.CATEGORY_PROFILE), (Date) anyObject());
+ }
+
+ private RulesProfile mockProfile(int version) {
+ RulesProfile profile = mock(RulesProfile.class);
+ when(profile.getId()).thenReturn(22);
+ when(profile.getName()).thenReturn("Profile");
+ when(profile.getVersion()).thenReturn(version); // New version
+ return profile;
+ }
+
+ private TimeMachine mockTM(Project project, double profileValue, double versionValue) {
+ return mockTM(project, new Measure(CoreMetrics.PROFILE, profileValue),
+ new Measure(CoreMetrics.PROFILE_VERSION, versionValue));
+ }
+
+ private TimeMachine mockTMWithNullVersion(Project project, double profileValue) {
+ return mockTM(project, new Measure(CoreMetrics.PROFILE, profileValue), null);
+ }
+
+ private TimeMachine mockTM(Project project, Measure result1, Measure result2) {
+ TimeMachine timeMachine = mock(TimeMachine.class);
+
+ when(timeMachine.getMeasures(any(TimeMachineQuery.class)))
+ .thenReturn(result1 == null ? Collections.<Measure> emptyList() : Arrays.asList(result1))
+ .thenReturn(result2 == null ? Collections.<Measure> emptyList() : Arrays.asList(result2));
+
+ return timeMachine;
+ }
+
+}
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.*;
import org.sonar.api.batch.SensorContext;
+import org.sonar.api.database.DatabaseSession;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.test.IsMeasure;
RulesProfile profile = mock(RulesProfile.class);
when(profile.getId()).thenReturn(22);
when(profile.getName()).thenReturn("fake");
+ when(profile.getVersion()).thenReturn(2);
SensorContext context = mock(SensorContext.class);
+ DatabaseSession session = mock(DatabaseSession.class);
- ProfileSensor sensor = new ProfileSensor(profile);
+ ProfileSensor sensor = new ProfileSensor(profile, session);
sensor.analyse(null, context);
verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.PROFILE, 22d)));
+ verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.PROFILE_VERSION, 2d)));
}
}
- complete the Derby DDL file used for unit tests : sonar-testing-harness/src/main/resources/org/sonar/test/persistence/sonar-test.ddl
*/
- public static final int LAST_VERSION = 201;
+ public static final int LAST_VERSION = 202;
public final static String TABLE_NAME = "schema_migrations";
<class>org.sonar.api.database.model.AsyncMeasureSnapshot</class>
<class>org.sonar.api.batch.Event</class>
<class>org.sonar.api.profiles.Alert</class>
-
+ <class>org.sonar.api.rules.ActiveRuleChange</class>
+ <class>org.sonar.api.rules.ActiveRuleParamChange</class>
+
<properties>
<property name="hibernate.current_session_context_class" value="thread"/>
<property name="hibernate.connection.release_mode" value="after_transaction"/>
import org.dbunit.dataset.CompositeDataSet;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
+import org.dbunit.dataset.ITable;
import org.dbunit.dataset.ReplacementDataSet;
+import org.dbunit.dataset.filter.DefaultColumnFilter;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.ext.hsqldb.HsqldbDataTypeFactory;
import org.dbunit.operation.DatabaseOperation;
}
protected final void checkTables(String testName, String... tables) {
+ checkTables(testName, new String[] {}, tables);
+ }
+
+ protected final void checkTables(String testName, String[] excludedColumnNames, String... tables) {
getSession().commit();
try {
IDataSet dataSet = getCurrentDataSet();
IDataSet expectedDataSet = getExpectedData(testName);
for (String table : tables) {
- Assertion.assertEquals(expectedDataSet.getTable(table), dataSet.getTable(table));
+ ITable filteredTable = DefaultColumnFilter.excludedColumnsTable(dataSet.getTable(table), excludedColumnNames);
+ Assertion.assertEquals(expectedDataSet.getTable(table), filteredTable);
}
} catch (DataSetException e) {
throw translateException("Error while checking results", e);
public class Event extends BaseIdentifiable {
public static final String CATEGORY_VERSION = "Version";
public static final String CATEGORY_ALERT = "Alert";
+ public static final String CATEGORY_PROFILE = "Profile";
@Column(name = "name", updatable = true, nullable = true, length = 50)
private String name;
return CATEGORY_VERSION.equalsIgnoreCase(category);
}
+ public boolean isProfileCategory() {
+ return CATEGORY_PROFILE.equalsIgnoreCase(category);
+ }
+
public Date getDate() {
return date;
}
*/
package org.sonar.api.batch;
+import org.apache.commons.lang.builder.EqualsBuilder;
+
import com.google.common.collect.Lists;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.sonar.api.measures.Metric;
.append("to", to)
.toString();
}
+
+ @Override
+ public boolean equals(Object obj) {
+ return EqualsBuilder.reflectionEquals(this, obj);
+ }
+
}
.setDomain(DOMAIN_GENERAL)
.create();
+ public static final String PROFILE_VERSION_KEY = "profile_version";
+ public static final Metric PROFILE_VERSION = new Metric.Builder(PROFILE_VERSION_KEY, "Profile version", Metric.ValueType.INT)
+ .setDescription("Selected quality profile version")
+ .setQualitative(false)
+ .setDomain(DOMAIN_GENERAL)
+ .create();
public static List<Metric> metrics = Lists.newLinkedList();
@Column(name = "name", updatable = true, nullable = false)
private String name;
+ @Column(name = "version", updatable = true, nullable = false)
+ private int version = 1;
+
@Column(name = "default_profile", updatable = true, nullable = false)
private Boolean defaultProfile = Boolean.FALSE;
@Column(name = "enabled", updatable = true, nullable = false)
private Boolean enabled = Boolean.TRUE;
+ @Column(name = "used_profile", updatable = true, nullable = false)
+ private Boolean used = Boolean.FALSE;
+
@Column(name = "language", updatable = true, nullable = false)
private String language;
this.name = s;
return this;
}
+
+ public int getVersion() {
+ return version;
+ }
+
+ public RulesProfile setVersion(int version) {
+ this.version = version;
+ return this;
+ }
+
+ public Boolean getUsed() {
+ return used;
+ }
+
+ public RulesProfile setUsed(Boolean used) {
+ this.used = used;
+ return this;
+ }
/**
* @return the list of active rules
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.api.rules;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.sonar.api.database.BaseIdentifiable;
+import org.sonar.api.profiles.RulesProfile;
+
+/**
+ * A class to map a RuleChange to the hibernate model
+ *
+ * @since 2.9
+ */
+@Entity
+@Table(name = "active_rule_changes")
+public class ActiveRuleChange extends BaseIdentifiable {
+
+ @Column(name = "user_login", updatable = false, nullable = false)
+ private String modifierLogin;
+
+ @ManyToOne(fetch = FetchType.EAGER)
+ @JoinColumn(name = "profile_id", updatable = false, nullable = false)
+ private RulesProfile rulesProfile;
+
+ @Column(name = "profile_version", updatable = false, nullable = false)
+ private int profileVersion;
+
+ @ManyToOne(fetch = FetchType.EAGER)
+ @JoinColumn(name = "rule_id", updatable = false, nullable = false)
+ private Rule rule;
+
+ @Column(name = "change_date", updatable = false, nullable = false)
+ private Date date;
+
+ /**
+ * true means rule was enabled
+ * false means rule was disabled
+ * null means rule stay enabled (another param was changed)
+ */
+ @Column(name = "enabled")
+ private Boolean enabled;
+
+ @Column(name = "old_severity", updatable = false, nullable = true)
+ @Enumerated(EnumType.ORDINAL)
+ private RulePriority oldSeverity;
+
+ @Column(name = "new_severity", updatable = false, nullable = true)
+ @Enumerated(EnumType.ORDINAL)
+ private RulePriority newSeverity;
+
+ @OneToMany(mappedBy = "activeRuleChange", fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE })
+ private List<ActiveRuleParamChange> activeRuleParamChanges = new ArrayList<ActiveRuleParamChange>();
+
+ public ActiveRuleChange(String modifierLogin, RulesProfile profile, Rule rule) {
+ this.modifierLogin = modifierLogin;
+ this.rulesProfile = profile;
+ this.profileVersion = profile.getVersion();
+ this.rule = rule;
+ this.date = Calendar.getInstance().getTime();
+ }
+
+ public Rule getRule() {
+ return rule;
+ }
+
+ public RulePriority getOldSeverity() {
+ return oldSeverity;
+ }
+
+ public void setOldSeverity(RulePriority oldSeverity) {
+ this.oldSeverity = oldSeverity;
+ }
+
+ public RulePriority getNewSeverity() {
+ return newSeverity;
+ }
+
+ public void setNewSeverity(RulePriority newSeverity) {
+ this.newSeverity = newSeverity;
+ }
+
+ public RulesProfile getRulesProfile() {
+ return rulesProfile;
+ }
+
+ public int getProfileVersion() {
+ return profileVersion;
+ }
+
+ public String getRepositoryKey() {
+ return rule.getRepositoryKey();
+ }
+
+ /**
+ * @return the config key the changed rule belongs to
+ */
+ public String getConfigKey() {
+ return rule.getConfigKey();
+ }
+
+ /**
+ * @return the key of the changed rule
+ */
+ public String getRuleKey() {
+ return rule.getKey();
+ }
+
+ public Boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(Boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public List<ActiveRuleParamChange> getActiveRuleParamChanges() {
+ return activeRuleParamChanges;
+ }
+
+ public String getModifierLogin() {
+ return modifierLogin;
+ }
+
+ public ActiveRuleChange setParameterChange(String key, String oldValue, String newValue) {
+ RuleParam ruleParameter = rule.getParam(key);
+ if (ruleParameter != null) {
+ activeRuleParamChanges.add(new ActiveRuleParamChange(this, ruleParameter, oldValue, newValue));
+ }
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (obj.getClass() != getClass()) {
+ return false;
+ }
+ ActiveRuleChange rhs = (ActiveRuleChange) obj;
+ return new EqualsBuilder()
+ .appendSuper(super.equals(obj))
+ .append(modifierLogin, rhs.modifierLogin)
+ .append(rulesProfile, rhs.rulesProfile)
+ .append(rule, rhs.rule)
+ .append(date, rhs.date)
+ .append(enabled, rhs.enabled)
+ .append(newSeverity, rhs.newSeverity)
+ .isEquals();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder(41, 33)
+ .append(modifierLogin)
+ .append(rulesProfile)
+ .append(rule)
+ .append(date)
+ .append(enabled)
+ .append(newSeverity)
+ .toHashCode();
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .append("id", getId())
+ .append("profile", rulesProfile)
+ .append("rule", rule)
+ .append("modifier", modifierLogin)
+ .append("changed at", date)
+ .append("enabled", enabled)
+ .append("new severity", newSeverity)
+ .toString();
+ }
+
+}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.api.rules;
+
+import org.sonar.api.database.BaseIdentifiable;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+
+import javax.persistence.*;
+
+/**
+ * @since 2.9
+ */
+@Entity
+@Table(name = "active_rule_param_changes")
+public class ActiveRuleParamChange extends BaseIdentifiable {
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "active_rule_change_id")
+ private ActiveRuleChange activeRuleChange;
+
+ @ManyToOne(fetch = FetchType.LAZY, optional = true)
+ @JoinColumn(name = "rules_parameter_id")
+ private RuleParam ruleParam;
+
+ @Column(name = "old_value", updatable = false, nullable = true, length = 4000)
+ private String oldValue;
+
+ @Column(name = "new_value", updatable = false, nullable = true, length = 4000)
+ private String newValue;
+
+ ActiveRuleParamChange(ActiveRuleChange activeRuleChange, RuleParam ruleParam, String oldValue, String newValue) {
+ this.activeRuleChange = activeRuleChange;
+ this.ruleParam = ruleParam;
+ this.oldValue = oldValue;
+ this.newValue = newValue;
+ }
+
+ public ActiveRuleChange getActiveRuleChange() {
+ return activeRuleChange;
+ }
+
+ public RuleParam getRuleParam() {
+ return ruleParam;
+ }
+
+ public String getOldValue() {
+ return oldValue;
+ }
+
+ public String getNewValue() {
+ return newValue;
+ }
+
+ public String getKey() {
+ return ruleParam.getKey();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ActiveRuleParamChange)) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ ActiveRuleParamChange other = (ActiveRuleParamChange) obj;
+ return new EqualsBuilder()
+ .append(getId(), other.getId()).isEquals();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder(17, 57)
+ .append(getId())
+ .toHashCode();
+ }
+
+}
profile.activateRule(rule, RulePriority.MINOR);
assertThat(profile.getActiveRule("repo", "key1").getSeverity(), is(RulePriority.MINOR));
}
+
+ @Test
+ public void defaultVersionIs1() {
+ RulesProfile profile = RulesProfile.create();
+ assertThat(profile.getVersion(), is(1));
+ }
}
}
public void importProfile(RulesDao rulesDao, RulesProfile toImport) {
- if (toImport.getEnabled()==null) {
+ if (toImport.getEnabled() == null) {
// backward-compatibility with versions < 2.6. The field "enabled" did not exist. Default value is true.
toImport.setEnabled(true);
}
+ if (toImport.getVersion() == 0) {
+ // backward-compatibility with versions < 2.9. The field "version" did not exist. Default value is 1.
+ toImport.setVersion(1);
+ }
+ if (toImport.getUsed() == null) {
+ // backward-compatibility with versions < 2.9. The field "used_profile" did not exist. Default value is false.
+ toImport.setUsed(false);
+ }
importActiveRules(rulesDao, toImport);
importAlerts(toImport);
session.save(toImport);
import org.sonar.api.database.model.ResourceModel;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.rules.ActiveRule;
+import org.sonar.api.rules.ActiveRuleChange;
import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleParam;
+import org.sonar.api.rules.RulePriority;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.jpa.dao.BaseDao;
import org.sonar.jpa.dao.RulesDao;
public void deleteProfile(int profileId) {
RulesProfile profile = getSession().getEntity(RulesProfile.class, profileId);
if (profile != null && !profile.getProvided() && getChildren(profile).isEmpty()) {
+ //Remove history of rule changes
+ String hqlDeleteRc = "DELETE " + ActiveRuleChange.class.getSimpleName() + " rc WHERE rc.rulesProfile=:rulesProfile";
+ getSession().createQuery(hqlDeleteRc).setParameter("rulesProfile", profile).executeUpdate();
+
String hql = "UPDATE " + ResourceModel.class.getSimpleName() + " o SET o.rulesProfile=null WHERE o.rulesProfile=:rulesProfile";
getSession().createQuery(hql).setParameter("rulesProfile", profile).executeUpdate();
getSession().remove(profile);
}
public void deleteAllProfiles() {
+ //Remove history of rule changes
+ String hqlDeleteRc = "DELETE " + ActiveRuleChange.class.getSimpleName() + " rc";
+ getSession().createQuery(hqlDeleteRc).executeUpdate();
+
String hql = "UPDATE " + ResourceModel.class.getSimpleName() + " o SET o.rulesProfile = null WHERE o.rulesProfile IS NOT NULL";
getSession().createQuery(hql).executeUpdate();
List profiles = getSession().createQuery("FROM " + RulesProfile.class.getSimpleName()).getResultList();
// Managing inheritance of profiles
- public ValidationMessages changeParentProfile(Integer profileId, String parentName) {
+ public ValidationMessages changeParentProfile(Integer profileId, String parentName, String userLogin) {
ValidationMessages messages = ValidationMessages.create();
RulesProfile profile = getSession().getEntity(RulesProfile.class, profileId);
if (profile != null && !profile.getProvided()) {
// Deactivate all inherited rules
if (oldParent != null) {
for (ActiveRule activeRule : oldParent.getActiveRules()) {
- deactivate(profile, activeRule.getRule());
+ deactivate(profile, activeRule.getRule(), userLogin);
}
}
// Activate all inherited rules
if (newParent != null) {
for (ActiveRule activeRule : newParent.getActiveRules()) {
- activateOrChange(profile, activeRule);
+ activateOrChange(profile, activeRule, userLogin);
}
}
profile.setParentName(newParent == null ? null : newParent.getName());
return messages;
}
+ /**
+ * Rule was activated
+ */
+ public void activated(int profileId, int activeRuleId, String userLogin) {
+ ActiveRule activeRule = getSession().getEntity(ActiveRule.class, activeRuleId);
+ RulesProfile profile = getSession().getEntity(RulesProfile.class, profileId);
+ ruleEnabled(profile, activeRule, userLogin);
+ //Notify child profiles
+ activatedOrChanged(profileId, activeRuleId, userLogin);
+ }
+
+ /**
+ * Rule param was changed
+ */
+ public void ruleParamChanged(int profileId, int activeRuleId, String paramKey, String oldValue, String newValue, String userLogin) {
+ ActiveRule activeRule = getSession().getEntity(ActiveRule.class, activeRuleId);
+ RulesProfile profile = getSession().getEntity(RulesProfile.class, profileId);
+
+ ruleParamChanged(profile, activeRule.getRule(), paramKey, oldValue, newValue, userLogin);
+
+ //Notify child profiles
+ activatedOrChanged(profileId, activeRuleId, userLogin);
+ }
+
+ /**
+ * Rule severity was changed
+ */
+ public void ruleSeverityChanged(int profileId, int activeRuleId, RulePriority oldSeverity, RulePriority newSeverity, String userLogin) {
+ ActiveRule activeRule = getSession().getEntity(ActiveRule.class, activeRuleId);
+ RulesProfile profile = getSession().getEntity(RulesProfile.class, profileId);
+
+ ruleSeverityChanged(profile, activeRule.getRule(), oldSeverity, newSeverity, userLogin);
+
+ //Notify child profiles
+ activatedOrChanged(profileId, activeRuleId, userLogin);
+ }
+
/**
* Rule was activated/changed in parent profile.
*/
- public void activatedOrChanged(int parentProfileId, int activeRuleId) {
+ private void activatedOrChanged(int parentProfileId, int activeRuleId, String userLogin) {
ActiveRule parentActiveRule = getSession().getEntity(ActiveRule.class, activeRuleId);
if (parentActiveRule.isInherited()) {
parentActiveRule.setInheritance(ActiveRule.OVERRIDES);
getSession().saveWithoutFlush(parentActiveRule);
}
for (RulesProfile child : getChildren(parentProfileId)) {
- activateOrChange(child, parentActiveRule);
+ activateOrChange(child, parentActiveRule, userLogin);
}
getSession().commit();
}
/**
* Rule was deactivated in parent profile.
*/
- public void deactivated(int parentProfileId, int ruleId) {
- Rule rule = getSession().getEntity(Rule.class, ruleId);
+ public void deactivated(int parentProfileId, int deactivatedRuleId, String userLogin) {
+ ActiveRule parentActiveRule = getSession().getEntity(ActiveRule.class, deactivatedRuleId);
+ RulesProfile profile = getSession().getEntity(RulesProfile.class, parentProfileId);
+ ruleDisabled(profile, parentActiveRule, userLogin);
for (RulesProfile child : getChildren(parentProfileId)) {
- deactivate(child, rule);
+ deactivate(child, parentActiveRule.getRule(), userLogin);
}
getSession().commit();
}
return false;
}
- public void revert(int profileId, int activeRuleId) {
+ public void revert(int profileId, int activeRuleId, String userLogin) {
RulesProfile profile = getSession().getEntity(RulesProfile.class, profileId);
- ActiveRule activeRule = getSession().getEntity(ActiveRule.class, activeRuleId);
- if (activeRule != null && activeRule.doesOverride()) {
- ActiveRule parentActiveRule = getParentProfile(profile).getActiveRule(activeRule.getRule());
- removeActiveRule(profile, activeRule);
- activeRule = (ActiveRule) parentActiveRule.clone();
- activeRule.setRulesProfile(profile);
- activeRule.setInheritance(ActiveRule.INHERITED);
- profile.addActiveRule(activeRule);
- getSession().saveWithoutFlush(activeRule);
+ ActiveRule oldActiveRule = getSession().getEntity(ActiveRule.class, activeRuleId);
+ if (oldActiveRule != null && oldActiveRule.doesOverride()) {
+ ActiveRule parentActiveRule = getParentProfile(profile).getActiveRule(oldActiveRule.getRule());
+ removeActiveRule(profile, oldActiveRule);
+ ActiveRule newActiveRule = (ActiveRule) parentActiveRule.clone();
+ newActiveRule.setRulesProfile(profile);
+ newActiveRule.setInheritance(ActiveRule.INHERITED);
+ profile.addActiveRule(newActiveRule);
+ getSession().saveWithoutFlush(newActiveRule);
+
+ //Compute change
+ ruleChanged(profile, oldActiveRule, newActiveRule, userLogin);
for (RulesProfile child : getChildren(profile)) {
- activateOrChange(child, activeRule);
+ activateOrChange(child, newActiveRule, userLogin);
}
getSession().commit();
}
}
+
+ private synchronized void incrementProfileVersionIfNeeded(RulesProfile profile) {
+ if (profile.getUsed()) {
+ profile.setVersion(profile.getVersion() + 1);
+ profile.setUsed(false);
+ getSession().saveWithoutFlush(profile);
+ }
+ }
+
+ /**
+ * Deal with creation of ActiveRuleChange item when a rule param is changed on a profile
+ */
+ private void ruleParamChanged(RulesProfile profile, Rule rule, String paramKey, String oldValue, String newValue, String userLogin) {
+ incrementProfileVersionIfNeeded(profile);
+ ActiveRuleChange rc = new ActiveRuleChange(userLogin, profile, rule);
+ if (oldValue != newValue) {
+ rc.setParameterChange(paramKey, oldValue, newValue);
+ getSession().saveWithoutFlush(rc);
+ }
+ }
- private void activateOrChange(RulesProfile profile, ActiveRule parentActiveRule) {
- ActiveRule activeRule = profile.getActiveRule(parentActiveRule.getRule());
- if (activeRule != null) {
- if (activeRule.isInherited()) {
- removeActiveRule(profile, activeRule);
+ /**
+ * Deal with creation of ActiveRuleChange item when a rule severity is changed on a profile
+ */
+ private void ruleSeverityChanged(RulesProfile profile, Rule rule, RulePriority oldSeverity, RulePriority newSeverity, String userLogin) {
+ incrementProfileVersionIfNeeded(profile);
+ ActiveRuleChange rc = new ActiveRuleChange(userLogin, profile, rule);
+ if (oldSeverity != newSeverity) {
+ rc.setOldSeverity(oldSeverity);
+ rc.setNewSeverity(newSeverity);
+ getSession().saveWithoutFlush(rc);
+ }
+ }
+
+ /**
+ * Deal with creation of ActiveRuleChange item when a rule is changed (severity and/or param(s)) on a profile
+ */
+ private void ruleChanged(RulesProfile profile, ActiveRule oldActiveRule, ActiveRule newActiveRule, String userLogin) {
+ incrementProfileVersionIfNeeded(profile);
+ ActiveRuleChange rc = new ActiveRuleChange(userLogin, profile, newActiveRule.getRule());
+
+ if (oldActiveRule.getSeverity() != newActiveRule.getSeverity()) {
+ rc.setOldSeverity(oldActiveRule.getSeverity());
+ rc.setNewSeverity(newActiveRule.getSeverity());
+ }
+ if (oldActiveRule.getRule().getParams() != null) {
+ for (RuleParam p : oldActiveRule.getRule().getParams()) {
+ String oldParam = oldActiveRule.getParameter(p.getKey());
+ String newParam = newActiveRule.getParameter(p.getKey());
+ if (oldParam != newParam) {
+ rc.setParameterChange(p.getKey(), oldParam, newParam);
+ }
+ }
+ }
+
+ getSession().saveWithoutFlush(rc);
+ }
+
+ /**
+ * Deal with creation of ActiveRuleChange item when a rule is enabled on a profile
+ */
+ private void ruleEnabled(RulesProfile profile, ActiveRule newActiveRule, String userLogin) {
+ incrementProfileVersionIfNeeded(profile);
+ ActiveRuleChange rc = new ActiveRuleChange(userLogin, profile, newActiveRule.getRule());
+ rc.setEnabled(true);
+ rc.setNewSeverity(newActiveRule.getSeverity());
+ if (newActiveRule.getRule().getParams() != null) {
+ for (RuleParam p : newActiveRule.getRule().getParams()) {
+ String newParam = newActiveRule.getParameter(p.getKey());
+ if (newParam != null) {
+ rc.setParameterChange(p.getKey(), null, newParam);
+ }
+ }
+ }
+ getSession().saveWithoutFlush(rc);
+ }
+
+ /**
+ * Deal with creation of ActiveRuleChange item when a rule is disabled on a profile
+ */
+ private void ruleDisabled(RulesProfile profile, ActiveRule disabledRule, String userLogin) {
+ incrementProfileVersionIfNeeded(profile);
+ ActiveRuleChange rc = new ActiveRuleChange(userLogin, profile, disabledRule.getRule());
+ rc.setEnabled(false);
+ rc.setOldSeverity(disabledRule.getSeverity());
+ if (disabledRule.getRule().getParams() != null) {
+ for (RuleParam p : disabledRule.getRule().getParams()) {
+ String oldParam = disabledRule.getParameter(p.getKey());
+ if (oldParam != null) {
+ rc.setParameterChange(p.getKey(), oldParam, null);
+ }
+ }
+ }
+ getSession().saveWithoutFlush(rc);
+ }
+
+ private void activateOrChange(RulesProfile profile, ActiveRule parentActiveRule, String userLogin) {
+ ActiveRule oldActiveRule = profile.getActiveRule(parentActiveRule.getRule());
+ if (oldActiveRule != null) {
+ if (oldActiveRule.isInherited()) {
+ removeActiveRule(profile, oldActiveRule);
} else {
- activeRule.setInheritance(ActiveRule.OVERRIDES);
- getSession().saveWithoutFlush(activeRule);
+ oldActiveRule.setInheritance(ActiveRule.OVERRIDES);
+ getSession().saveWithoutFlush(oldActiveRule);
return; // no need to change in children
}
}
- activeRule = (ActiveRule) parentActiveRule.clone();
- activeRule.setRulesProfile(profile);
- activeRule.setInheritance(ActiveRule.INHERITED);
- profile.addActiveRule(activeRule);
- getSession().saveWithoutFlush(activeRule);
+ ActiveRule newActiveRule = (ActiveRule) parentActiveRule.clone();
+ newActiveRule.setRulesProfile(profile);
+ newActiveRule.setInheritance(ActiveRule.INHERITED);
+ profile.addActiveRule(newActiveRule);
+ getSession().saveWithoutFlush(newActiveRule);
+
+ if (oldActiveRule != null) {
+ ruleChanged(profile, oldActiveRule, newActiveRule, userLogin);
+ }
+ else {
+ ruleEnabled(profile, newActiveRule, userLogin);
+ }
for (RulesProfile child : getChildren(profile)) {
- activateOrChange(child, activeRule);
+ activateOrChange(child, newActiveRule, userLogin);
}
}
- private void deactivate(RulesProfile profile, Rule rule) {
+ private void deactivate(RulesProfile profile, Rule rule, String userLogin) {
ActiveRule activeRule = profile.getActiveRule(rule);
if (activeRule != null) {
if (activeRule.isInherited()) {
+ ruleDisabled(profile, activeRule, userLogin);
removeActiveRule(profile, activeRule);
} else {
activeRule.setInheritance(null);
}
for (RulesProfile child : getChildren(profile)) {
- deactivate(child, rule);
+ deactivate(child, rule, userLogin);
}
}
}
import org.sonar.api.profiles.ProfileExporter;
import org.sonar.api.profiles.ProfileImporter;
import org.sonar.api.resources.Language;
+import org.sonar.api.rules.RulePriority;
import org.sonar.api.rules.RuleRepository;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.api.web.*;
getProfilesManager().deleteProfile((int) profileId);
}
- public ValidationMessages changeParentProfile(int profileId, String parentName) {
- return getProfilesManager().changeParentProfile(profileId, parentName);
+ public ValidationMessages changeParentProfile(int profileId, String parentName, String userLogin) {
+ return getProfilesManager().changeParentProfile(profileId, parentName, userLogin);
}
- public void ruleActivatedOrChanged(int parentProfileId, int activeRuleId) {
- getProfilesManager().activatedOrChanged(parentProfileId, activeRuleId);
+ public void ruleActivated(int parentProfileId, int activeRuleId, String userLogin) {
+ getProfilesManager().activated(parentProfileId, activeRuleId, userLogin);
}
- public void ruleDeactivated(int parentProfileId, int ruleId) {
- getProfilesManager().deactivated(parentProfileId, ruleId);
+ public void ruleParamChanged(int parentProfileId, int activeRuleId, String paramKey, String oldValue, String newValue, String userLogin) {
+ getProfilesManager().ruleParamChanged(parentProfileId, activeRuleId, paramKey, oldValue, newValue, userLogin);
}
- public void revertRule(int profileId, int activeRuleId) {
- getProfilesManager().revert(profileId, activeRuleId);
+ public void ruleSeverityChanged(int parentProfileId, int activeRuleId, int oldSeverityId, int newSeverityId, String userLogin) {
+ getProfilesManager().ruleSeverityChanged(parentProfileId, activeRuleId, RulePriority.values()[oldSeverityId],
+ RulePriority.values()[newSeverityId], userLogin);
+ }
+
+ public void ruleDeactivated(int parentProfileId, int deactivatedRuleId, String userLogin) {
+ getProfilesManager().deactivated(parentProfileId, deactivatedRuleId, userLogin);
+ }
+
+ public void revertRule(int profileId, int activeRuleId, String userLogin) {
+ getProfilesManager().revert(profileId, activeRuleId, userLogin);
}
public List<Footer> getWebFooters() {
profiles=Profile.find(:all, :conditions => ['language=? and id<>? and (parent_name is null or parent_name<>?) and enabled=?', @profile.language, @profile.id, @profile.name, true], :order => 'name')
@select_parent = [['None', nil]] + profiles.collect{ |profile| [profile.name, profile.name] }
end
-
+
+ #
+ #
+ # GET /profiles/changelog?id=<profile id>
+ #
+ #
+ def changelog
+ @profile = Profile.find(params[:id])
+
+ @changes=ActiveRuleChange.find(:all, :conditions => ['profile_id=?', @profile.id], :order => 'id desc')
+
+ end
#
id = params[:id].to_i
parent_name = params[:parent_name]
if parent_name.blank?
- messages = java_facade.changeParentProfile(id, nil)
+ messages = java_facade.changeParentProfile(id, nil, current_user.login)
else
- messages = java_facade.changeParentProfile(id, parent_name)
+ messages = java_facade.changeParentProfile(id, parent_name, current_user.login)
end
flash_validation_messages(messages)
redirect_to :action => 'inheritance', :id => id
def revert_rule
id = params[:id].to_i
rule_id = params[:active_rule_id].to_i
- java_facade.revertRule(id, rule_id)
+ java_facade.revertRule(id, rule_id, current_user.login)
redirect_to request.query_parameters.merge({:action => 'index', :id => params[:id], :commit => nil})
end
active_rule=profile.active_by_rule_id(rule.id)
if priority.blank?
# deactivate the rule
- active_rule.destroy if active_rule
- active_rule=nil
- java_facade.ruleDeactivated(profile.id, rule.id)
+ if active_rule
+ java_facade.ruleDeactivated(profile.id, active_rule.id, current_user.login)
+ active_rule.destroy
+ active_rule=nil
+ end
else
# activate the rule
+ activated = false
if active_rule.nil?
active_rule = ActiveRule.new(:profile_id => profile.id, :rule => rule)
rule.parameters.select{|p| p.default_value.present?}.each do |p|
active_rule.active_rule_parameters.build(:rules_parameter => p, :value => p.default_value)
end
+ activated = true
end
+ old_severity = active_rule.failure_level
active_rule.failure_level=Sonar::RulePriority.id(priority)
active_rule.save!
- java_facade.ruleActivatedOrChanged(profile.id, active_rule.id)
+ if activated
+ java_facade.ruleActivated(profile.id, active_rule.id, current_user.login)
+ else
+ java_facade.ruleSeverityChanged(profile.id, active_rule.id, old_severity, active_rule.failure_level, current_user.login)
+ end
end
if active_rule
active_rule.reload
if !profile.provided?
if value != ""
active_param = ActiveRuleParameter.new(:rules_parameter => rule_param, :active_rule => active_rule ) if active_param.nil?
+ old_value = active_param.value
active_param.value = value
active_param.save
active_param.valid?
active_param.reload
+ java_facade.ruleParamChanged(profile.id, active_rule.id, rule_param.name, old_value, value, current_user.login)
elsif !active_param.nil?
+ old_value = active_param.value
active_param.destroy
active_param = nil
+ java_facade.ruleParamChanged(profile.id, active_rule.id, rule_param.name, old_value, nil, current_user.login)
end
- java_facade.ruleActivatedOrChanged(profile.id, active_rule.id)
end
render :partial => 'rule_param', :object => nil,
:locals => {:parameter => rule_param, :active_parameter => active_param, :profile => profile, :active_rule => active_rule, :is_admin => is_admin }
count = rules_to_activate.size
rules_to_activate.each do |rule|
active_rule = profile.active_rules.create(:rule => rule, :failure_level => rule.priority)
- java_facade.ruleActivatedOrChanged(profile.id, active_rule.id)
+ java_facade.ruleActivated(profile.id, active_rule.id, current_user.login)
end
end
count
profile.active_rules.each do |ar|
if rule_ids.include?(ar.rule_id) && !ar.inheritance.present?
ar.destroy
- java_facade.ruleDeactivated(profile.id, ar.rule_id)
+ java_facade.ruleDeactivated(profile.id, ar.rule_id, current_user.login)
count+=1
end
end
--- /dev/null
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2011 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# Sonar 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.
+#
+# Sonar 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 Sonar; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+#
+class ActiveRuleChange < ActiveRecord::Base
+ belongs_to :rules_profile, :class_name => 'Profile', :foreign_key => 'profile_id'
+ belongs_to :rule
+ has_many :active_rule_param_changes, :dependent => :destroy
+
+ def old_severity_text
+ Sonar::RulePriority.to_s old_severity
+ end
+
+ def new_severity_text
+ Sonar::RulePriority.to_s new_severity
+ end
+
+ def parameters
+ active_rule_param_changes
+ end
+
+end
--- /dev/null
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2011 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# Sonar 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.
+#
+# Sonar 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 {library}; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+#
+ class ActiveRuleParamChange < ActiveRecord::Base
+ belongs_to :active_rule_change
+ belongs_to :rules_parameter
+
+ def name
+ rules_parameter.name
+ end
+
+ def parameter
+ rules_parameter
+ end
+
+ end
KEY_VERSION='Version'
KEY_ALERT='Alert'
+ KEY_PROFILE='Profile'
def initialize(name=nil, description=nil)
@name=name
end
def editable?
- !([KEY_VERSION, KEY_ALERT].include?(name))
+ !([KEY_VERSION, KEY_ALERT, KEY_PROFILE].include?(name))
end
def self.defaults
[
EventCategory.new(KEY_VERSION, 'Application version'),
- EventCategory.new(KEY_ALERT, 'Alert')
+ EventCategory.new(KEY_ALERT, 'Alert'),
+ EventCategory.new(KEY_PROFILE, 'Profile change')
]
end
<li>
<a href="<%= url_for :controller => 'profiles', :action => 'inheritance', :id => @profile.id -%>" <%= "class='selected'" if selected_tab=='inheritance' -%>>Profile inheritance</a>
</li>
+ <li>
+ <a href="<%= url_for :controller => 'profiles', :action => 'changelog', :id => @profile.id -%>" <%= "class='selected'" if selected_tab=='changelog' -%>>Changelog</a>
+ </li>
<% if new_tab %>
<li>
<a href="#" class='selected'><%= new_tab -%></a>
--- /dev/null
+<h1 class="marginbottom10"><%= link_to 'Quality profiles', :controller => 'profiles', :action => 'index' -%> / <%= h @profile.language -%> / <%= h @profile.name %></h1>
+<%= render :partial => 'profiles/tabs', :locals => {:selected_tab=>'changelog'} %>
+
+<div class="tabs-panel marginbottom10">
+
+ <table class="data width100">
+ <thead>
+ <tr>
+ <th>Action</th>
+ <th>By</th>
+ <th>Date</th>
+ <th>Rule name</th>
+ <th>Parameters</th>
+ </tr>
+ </thead>
+ <% current_version = -1
+ @changes.each do |change|
+ %>
+ <% if current_version != change.profile_version %>
+ <tr>
+ <td align="left" colspan="5">
+ <div class="line-block">
+ <h2>Version <%=change.profile_version%></h2>
+ </div>
+ </td>
+ </tr>
+ <% current_version = change.profile_version
+ end
+ %>
+ <tr class="<%= cycle 'even', 'odd', :name => change.profile_version -%>">
+ <td valign="top"><%=case change.enabled
+ when true then "Enabled"
+ when false then "Disabled"
+ when nil then "Modified"
+ end%></td>
+ <td valign="top"><%=change.user_login%></td>
+ <td valign="top"><%=change.change_date.strftime("%Y-%m-%d %H:%M:%S")%></td>
+ <td valign="top"><%=change.rule.name%></td>
+ <td valign="top">
+ <% if change.old_severity
+ if change.new_severity %>
+ Severity changed from <i><%= change.old_severity_text %></i> to
+ <% else %>
+ Severity was <i><%= change.old_severity_text %></i>
+ <% end
+ end %>
+ <% if change.new_severity
+ if change.old_severity %>
+ <i><%= change.new_severity_text %></i>
+ <% else %>
+ Severity set to <i><%= change.new_severity_text %></i>
+ <% end
+ end %>
+ <% if (change.old_severity or change.new_severity) and change.parameters.size > 0 %>
+ <br/>
+ <% end %>
+ <% change.parameters.each do |param_change| %>
+ Parameter <i><%=param_change.name %></i>
+ <% if not param_change.old_value %>
+ set to <i><%= param_change.new_value %></i>
+ <% elsif not param_change.new_value
+ if change.enabled == false %>
+ was <i><%= param_change.old_value %></i>
+ <% else %>
+ reset to default value (was <i><%= param_change.old_value %></i>)
+ <% end
+ else %>
+ changed from <i><%= param_change.old_value %></i> to <i><%= param_change.new_value %></i>
+ <% end %>
+ <%= "<br/>" unless param_change == change.parameters.last %>
+ <% end%>
+ </td>
+ </tr>
+ <% end %>
+ </table>
+
+</div>
<thead>
<tr>
<th class="left">Name</th>
+ <th align="left">Version</th>
<th class="right">Rules</th>
<th class="right">Alerts</th>
<th class="right">Projects</th>
<tr class="<%= cycle 'even', 'odd', :name => language.getKey() -%>" id="<%= u profile.key %>">
<td><a href="<%= url_for :controller => 'rules_configuration', :action => 'index', :id => profile.id -%>" id="rules-<%= language.getKey() -%>-<%= u(profile.name) -%>"><%= h profile.name %></a></td>
+ <td align="left"><span id="version_<%= u profile.key -%>"><%= profile.version -%></span></td>
+
<td align="right">
<span id="activated_rules_<%= u profile.key -%>"><%= profile.count_active_rules -%></span>
</td>
--- /dev/null
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2011 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# Sonar 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.
+#
+# Sonar 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 Sonar; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+#
+
+#
+# Sonar 2.9
+#
+class CreateRuleChanges < ActiveRecord::Migration
+
+ def self.up
+ create_table :active_rule_changes do |t|
+ t.column :user_login, :string, :limit => 40, :null => false
+ t.column :profile_id, :integer, :null => false
+ t.column :profile_version, :integer, :null => false
+ t.column :rule_id, :integer, :null => false
+ t.column :change_date, :datetime, :null => false
+ t.column :enabled, :boolean, :null => true
+ t.column :old_severity, :integer, :null => true
+ t.column :new_severity, :integer, :null => true
+ end
+ add_index :active_rule_changes, [:profile_id], :name => 'active_rule_changes_pid'
+
+ create_table :active_rule_param_changes do |t|
+ t.column :active_rule_change_id, :integer, :null => false
+ t.column :rules_parameter_id, :integer, :null => false
+ t.column :old_value, :string, :limit => 4000, :null => true
+ t.column :new_value, :string, :limit => 4000, :null => true
+ end
+ add_index :active_rule_param_changes, [:active_rule_change_id], :name => 'active_rule_param_changes_cid'
+
+ add_column 'rules_profiles', 'version', :integer, :default => 1
+ add_column 'rules_profiles', 'used_profile', :boolean, :default => false
+ Profile.reset_column_information
+ Profile.update_all(Profile.sanitize_sql_for_assignment({:used_profile => false, :version => 1}))
+ end
+
+end
@Test
public void shouldSetParent() {
setupData("shouldSetParent");
- profilesManager.changeParentProfile(2, "parent");
+ profilesManager.changeParentProfile(2, "parent", "admin");
checkTables("shouldSetParent", "active_rules", "rules_profiles");
}
@Test
public void shouldChangeParent() {
setupData("shouldChangeParent");
- profilesManager.changeParentProfile(3, "new_parent");
+ profilesManager.changeParentProfile(3, "new_parent", "admin");
checkTables("shouldChangeParent", "active_rules", "rules_profiles");
}
@Test
public void shouldRemoveParent() {
setupData("shouldRemoveParent");
- profilesManager.changeParentProfile(2, null);
+ profilesManager.changeParentProfile(2, null, "admin");
checkTables("shouldRemoveParent", "active_rules", "rules_profiles");
}
@Test
public void shouldDeactivateInChildren() {
setupData("shouldDeactivateInChildren");
- profilesManager.deactivated(1, 1);
+ profilesManager.deactivated(1, 1, "admin");
checkTables("shouldDeactivateInChildren", "active_rules", "rules_profiles");
}
@Test
public void shouldActivateInChildren() {
setupData("shouldActivateInChildren");
- profilesManager.activatedOrChanged(1, 1);
+ profilesManager.activated(1, 1, "admin");
checkTables("shouldActivateInChildren", "active_rules", "rules_profiles", "active_rule_parameters");
}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.server.configuration;
+
+import org.sonar.api.rules.RulePriority;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.jpa.test.AbstractDbUnitTestCase;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+
+public class RuleChangeTest extends AbstractDbUnitTestCase {
+ private ProfilesManager profilesManager;
+
+ @Before
+ public void setUp() {
+ profilesManager = new ProfilesManager(getSession(), null);
+ }
+
+ @Test
+ public void testVersionIncreaseIfUsed() {
+ setupData("initialData");
+ profilesManager.activated(2, 3, "admin");
+ checkTables("versionIncreaseIfUsed", "rules_profiles");
+ }
+
+ @Test
+ public void testVersionIncreaseIfUsedAndInChildren() {
+ setupData("initialData");
+ profilesManager.activated(1, 1, "admin");
+ checkTables("versionIncreaseIfUsedAndInChildren", "rules_profiles");
+ }
+
+ @Test
+ public void testRuleActivated() {
+ setupData("initialData");
+ profilesManager.activated(2, 3, "admin");
+ checkTables("ruleActivated", new String[] {"change_date"}, "active_rule_changes");
+ }
+
+ @Test
+ public void testRuleDeactivated() {
+ setupData("initialData");
+ profilesManager.deactivated(2, 3, "admin");
+ checkTables("ruleDeactivated", new String[] {"change_date"}, "active_rule_changes");
+ }
+
+ @Test
+ public void testRuleParamChanged() {
+ setupData("initialData");
+ profilesManager.ruleParamChanged(2, 3, "param1", "20", "30", "admin");
+ checkTables("ruleParamChanged", new String[] {"change_date"}, "active_rule_changes", "active_rule_param_changes");
+ }
+
+ @Test
+ public void testRuleSeverityChanged() {
+ setupData("initialData");
+ profilesManager.ruleSeverityChanged(2, 3, RulePriority.BLOCKER, RulePriority.CRITICAL, "admin");
+ checkTables("ruleSeverityChanged", new String[] {"change_date"}, "active_rule_changes");
+ }
+
+ @Test
+ public void testRuleReverted() {
+ setupData("ruleReverted");
+ profilesManager.revert(2, 3, "admin");
+ checkTables("ruleReverted", new String[] {"change_date"}, "active_rule_changes", "active_rule_param_changes");
+ }
+
+ @Test
+ public void testChangeParentProfile() {
+ setupData("changeParentProfile");
+ profilesManager.changeParentProfile(2, "parent", "admin");
+ checkTables("changeParentProfile", new String[] {"change_date"}, "active_rule_changes");
+ }
+
+
+}
<profiles>
<profile>
<name><![CDATA[test name]]></name>
+ <version><![CDATA[1]]></version>
<default-profile><![CDATA[true]]></default-profile>
<provided><![CDATA[true]]></provided>
+ <used><![CDATA[false]]></used>
<language><![CDATA[test language]]></language>
<enabled><![CDATA[true]]></enabled>
<active-rules>
</profile>
<profile>
<name><![CDATA[test2 name]]></name>
+ <version><![CDATA[1]]></version>
<default-profile><![CDATA[false]]></default-profile>
<provided><![CDATA[false]]></provided>
<language><![CDATA[test language]]></language>
<enabled><![CDATA[true]]></enabled>
+ <used><![CDATA[false]]></used>
<parentName><![CDATA[test name]]></parentName>
<active-rules>
<active-rule>
<rules_parameters id="1" rule_id="1" name="param1" description="[null]" param_type="r"/>
- <rules_profiles id="1" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="1" version="2" used_profile="false" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="2" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
+ <rules_profiles id="2" version="2" used_profile="false" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
<active_rules id="1" profile_id="1" rule_id="1" failure_level="2" inheritance="[null]"/>
<active_rule_parameters id="1" active_rule_id="1" rules_parameter_id="1" value="30"/>
<rules_parameters id="1" rule_id="1" name="param1" description="[null]" param_type="r"/>
- <rules_profiles id="1" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="2" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
<active_rules id="1" profile_id="1" rule_id="1" failure_level="2" inheritance="[null]"/>
<active_rule_parameters id="1" active_rule_id="1" rules_parameter_id="1" value="30"/>
<rules id="2" name="bar" description="test" plugin_config_key="checker/bar"
plugin_rule_key="checkstyle.rule2" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
- <rules_profiles id="1" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="2" provided="false" name="new_parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="new_parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="3" provided="false" name="child" default_profile="0" language="java" parent_name="new_parent" enabled="true"/>
+ <rules_profiles id="3" version="2" used_profile="false" provided="false" name="child" default_profile="0" language="java" parent_name="new_parent" enabled="true"/>
<active_rules id="1" profile_id="1" rule_id="1" failure_level="2" inheritance="[null]"/>
<rules id="2" name="bar" description="test" plugin_config_key="checker/bar"
plugin_rule_key="checkstyle.rule2" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
- <rules_profiles id="1" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="2" provided="false" name="new_parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="new_parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="3" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
+ <rules_profiles id="3" version="1" used_profile="true" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
<active_rules id="1" profile_id="1" rule_id="1" failure_level="2" inheritance="[null]"/>
<rules id="1" name="foo" description="test" plugin_config_key="checker/foo"
plugin_rule_key="checkstyle.rule1" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
- <rules_profiles id="1" provided="false" name="level1" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="level1" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="2" provided="false" name="level2" default_profile="0" language="java" parent_name="level1" enabled="true"/>
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="level2" default_profile="0" language="java" parent_name="level1" enabled="true"/>
- <rules_profiles id="3" provided="false" name="level3" default_profile="0" language="java" parent_name="level2" enabled="true"/>
+ <rules_profiles id="3" version="1" used_profile="true" provided="false" name="level3" default_profile="0" language="java" parent_name="level2" enabled="true"/>
</dataset>
<rules id="1" name="foo" description="test" plugin_config_key="checker/foo"
plugin_rule_key="checkstyle.rule1" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
- <rules_profiles id="1" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="1" version="2" used_profile="false" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="2" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
+ <rules_profiles id="2" version="2" used_profile="false" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
<active_rules id="1" profile_id="1" rule_id="1" failure_level="2" inheritance="[null]"/>
<rules id="1" name="foo" description="test" plugin_config_key="checker/foo"
plugin_rule_key="checkstyle.rule1" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
- <rules_profiles id="1" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="2" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
<active_rules id="1" profile_id="1" rule_id="1" failure_level="2" inheritance="[null]"/>
<rules id="1" name="foo" description="test" plugin_config_key="checker/foo"
plugin_rule_key="checkstyle.rule1" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
- <rules_profiles id="1" provided="false" name="level1" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="level1" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="2" provided="false" name="level2" default_profile="0" language="java" parent_name="level1" enabled="true"/>
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="level2" default_profile="0" language="java" parent_name="level1" enabled="true"/>
- <rules_profiles id="3" provided="false" name="level3" default_profile="0" language="java" parent_name="level2" enabled="true"/>
+ <rules_profiles id="3" version="1" used_profile="true" provided="false" name="level3" default_profile="0" language="java" parent_name="level2" enabled="true"/>
</dataset>
<rules id="1" name="foo" description="test" plugin_config_key="checker/foo"
plugin_rule_key="checkstyle.rule1" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
- <rules_profiles id="1" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="2" provided="false" name="child" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="2" version="2" used_profile="false" provided="false" name="child" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
<active_rules id="1" profile_id="1" rule_id="1" failure_level="2" inheritance="[null]"/>
<rules id="1" name="foo" description="test" plugin_config_key="checker/foo"
plugin_rule_key="checkstyle.rule1" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
- <rules_profiles id="1" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="2" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
<active_rules id="1" profile_id="1" rule_id="1" failure_level="2" inheritance="[null]"/>
<rules id="1" name="foo" description="test" plugin_config_key="checker/foo"
plugin_rule_key="checkstyle.rule1" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
- <rules_profiles id="1" provided="false" name="newName" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="newName" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="2" provided="false" name="level2" default_profile="0" language="java" parent_name="newName" enabled="true"/>
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="level2" default_profile="0" language="java" parent_name="newName" enabled="true"/>
- <rules_profiles id="3" provided="false" name="level3" default_profile="0" language="java" parent_name="level2" enabled="true"/>
+ <rules_profiles id="3" version="1" used_profile="true" provided="false" name="level3" default_profile="0" language="java" parent_name="level2" enabled="true"/>
</dataset>
<rules id="1" name="foo" description="test" plugin_config_key="checker/foo"
plugin_rule_key="checkstyle.rule1" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
- <rules_profiles id="1" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="2" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
+ <rules_profiles id="2" version="2" used_profile="false" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
<active_rules id="1" profile_id="1" rule_id="1" failure_level="2" inheritance="[null]"/>
<rules id="1" name="foo" description="test" plugin_config_key="checker/foo"
plugin_rule_key="checkstyle.rule1" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
- <rules_profiles id="1" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
- <rules_profiles id="2" provided="false" name="child" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="child" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
<active_rules id="1" profile_id="1" rule_id="1" failure_level="2" inheritance="[null]"/>
--- /dev/null
+<dataset>
+
+ <active_rule_changes id="1" user_login="admin" profile_id="2" profile_version="2" rule_id="1" enabled="true" old_severity="[null]" new_severity="2"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <rules id="1" name="foo" description="test" plugin_config_key="checker/foo"
+ plugin_rule_key="checkstyle.rule1" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
+
+ <rules id="2" name="bar" description="test2" plugin_config_key="checker/bar"
+ plugin_rule_key="checkstyle.rule2" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
+ <rules_parameters id="13" rule_id="2" name="param1" description="[null]" param_type="r"/>
+
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="child" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+
+ <active_rules id="1" profile_id="1" rule_id="1" failure_level="2" inheritance="[null]"/>
+
+ <active_rules id="3" profile_id="1" rule_id="2" failure_level="2" inheritance="[null]"/>
+ <active_rule_parameters id="1" active_rule_id="3" rules_parameter_id="13" value="30"/>
+
+ <active_rules id="4" profile_id="2" rule_id="2" failure_level="2" inheritance="[null]"/>
+ <active_rule_parameters id="2" active_rule_id="4" rules_parameter_id="13" value="60"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <rules id="1" name="foo" description="test" plugin_config_key="checker/foo"
+ plugin_rule_key="checkstyle.rule1" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
+
+ <rules id="2" name="bar" description="test2" plugin_config_key="checker/bar"
+ plugin_rule_key="checkstyle.rule2" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
+ <rules_parameters id="13" rule_id="2" name="param1" description="[null]" param_type="r"/>
+
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
+
+ <active_rules id="1" profile_id="1" rule_id="1" failure_level="2" inheritance="[null]"/>
+
+ <active_rules id="2" profile_id="2" rule_id="1" failure_level="2" inheritance="INHERITED"/>
+
+ <active_rules id="3" profile_id="2" rule_id="2" failure_level="2" inheritance="[null]"/>
+ <active_rule_parameters id="1" active_rule_id="3" rules_parameter_id="13" value="30"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <active_rule_changes id="1" user_login="admin" profile_id="2" profile_version="2" rule_id="2" enabled="true" old_severity="[null]" new_severity="2"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <active_rule_changes id="1" user_login="admin" profile_id="2" profile_version="2" rule_id="2" enabled="false" old_severity="2" new_severity="[null]"/>
+
+ <active_rule_param_changes id="1" active_rule_change_id="1" rules_parameter_id="13" old_value="30" new_value="[null]"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <active_rule_changes id="1" user_login="admin" profile_id="2" profile_version="2" rule_id="2" enabled="[null]" old_severity="[null]" new_severity="[null]"/>
+
+ <active_rule_param_changes id="1" active_rule_change_id="1" rules_parameter_id="13" old_value="20" new_value="30"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <active_rule_changes id="1" user_login="admin" profile_id="2" profile_version="2" rule_id="2" enabled="[null]" old_severity="3" new_severity="2"/>
+
+ <active_rule_param_changes id="1" active_rule_change_id="1" rules_parameter_id="13" old_value="30" new_value="[null]"/>
+ <active_rule_param_changes id="2" active_rule_change_id="1" rules_parameter_id="14" old_value="100" new_value="50"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <rules id="2" name="bar" description="test2" plugin_config_key="checker/bar"
+ plugin_rule_key="checkstyle.rule2" plugin_name="plugin" enabled="true" cardinality="SINGLE" parent_id="[null]"/>
+ <rules_parameters id="13" rule_id="2" name="param1" description="[null]" param_type="r"/>
+ <rules_parameters id="14" rule_id="2" name="param2" description="[null]" param_type="r"/>
+
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
+
+ <active_rules id="2" profile_id="1" rule_id="2" failure_level="2" inheritance="[null]"/>
+ <active_rule_parameters id="3" active_rule_id="2" rules_parameter_id="14" value="50"/>
+
+ <active_rules id="3" profile_id="2" rule_id="2" failure_level="3" inheritance="OVERRIDES"/>
+ <active_rule_parameters id="1" active_rule_id="3" rules_parameter_id="13" value="30"/>
+ <active_rule_parameters id="2" active_rule_id="3" rules_parameter_id="14" value="100"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <active_rule_changes id="1" user_login="admin" profile_id="2" profile_version="2" rule_id="2" enabled="[null]" old_severity="4" new_severity="3"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <rules_profiles id="1" version="1" used_profile="true" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+
+ <rules_profiles id="2" version="2" used_profile="false" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <rules_profiles id="1" version="2" used_profile="false" provided="false" name="parent" default_profile="0" language="java" parent_name="[null]" enabled="true"/>
+
+ <rules_profiles id="2" version="2" used_profile="false" provided="false" name="child" default_profile="0" language="java" parent_name="parent" enabled="true"/>
+
+</dataset>
<dataset>
- <rules_profiles id="1" provided="true" name="Java 1" default_profile="0" language="java" enabled="true" PARENT_NAME="[null]"/>
- <rules_profiles id="2" provided="false" name="Java 2" default_profile="1" language="java" enabled="true" PARENT_NAME="[null]"/>
- <rules_profiles id="3" provided="true" name="Php" default_profile="0" language="php" enabled="true" PARENT_NAME="[null]"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="true" name="Java 1" default_profile="0" language="java" enabled="true" PARENT_NAME="[null]"/>
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="Java 2" default_profile="1" language="java" enabled="true" PARENT_NAME="[null]"/>
+ <rules_profiles id="3" version="1" used_profile="true" provided="true" name="Php" default_profile="0" language="php" enabled="true" PARENT_NAME="[null]"/>
<!-- disabled -->
- <rules_profiles id="4" provided="true" name="Cobol 1" default_profile="1" language="cobol" enabled="false" PARENT_NAME="[null]"/>
- <rules_profiles id="5" provided="false" name="Cobol 2" default_profile="0" language="cobol" enabled="false" PARENT_NAME="[null]"/>
+ <rules_profiles id="4" version="1" used_profile="true" provided="true" name="Cobol 1" default_profile="1" language="cobol" enabled="false" PARENT_NAME="[null]"/>
+ <rules_profiles id="5" version="1" used_profile="true" provided="false" name="Cobol 2" default_profile="0" language="cobol" enabled="false" PARENT_NAME="[null]"/>
</dataset>
\ No newline at end of file
<dataset>
- <rules_profiles id="1" provided="true" name="Java 1" default_profile="0" language="java" enabled="true" PARENT_NAME="[null]"/>
- <rules_profiles id="2" provided="false" name="Java 2" default_profile="1" language="java" enabled="true" PARENT_NAME="[null]"/>
- <rules_profiles id="3" provided="true" name="Php" default_profile="0" language="php" enabled="true" PARENT_NAME="[null]"/>
- <rules_profiles id="4" provided="true" name="Cobol 1" default_profile="1" language="cobol" enabled="true" PARENT_NAME="[null]"/>
- <rules_profiles id="5" provided="false" name="Cobol 2" default_profile="0" language="cobol" enabled="true" PARENT_NAME="[null]"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="true" name="Java 1" default_profile="0" language="java" enabled="true" PARENT_NAME="[null]"/>
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="Java 2" default_profile="1" language="java" enabled="true" PARENT_NAME="[null]"/>
+ <rules_profiles id="3" version="1" used_profile="true" provided="true" name="Php" default_profile="0" language="php" enabled="true" PARENT_NAME="[null]"/>
+ <rules_profiles id="4" version="1" used_profile="true" provided="true" name="Cobol 1" default_profile="1" language="cobol" enabled="true" PARENT_NAME="[null]"/>
+ <rules_profiles id="5" version="1" used_profile="true" provided="false" name="Cobol 2" default_profile="0" language="cobol" enabled="true" PARENT_NAME="[null]"/>
</dataset>
\ No newline at end of file
<dataset>
- <rules_profiles id="1" provided="true" name="Java 1" default_profile="0" language="java" enabled="true" PARENT_NAME="[null]"/>
- <rules_profiles id="2" provided="false" name="Java 2" default_profile="1" language="java" enabled="true" PARENT_NAME="[null]"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="true" name="Java 1" default_profile="0" language="java" enabled="true" PARENT_NAME="[null]"/>
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="Java 2" default_profile="1" language="java" enabled="true" PARENT_NAME="[null]"/>
<!-- enabled -->
- <rules_profiles id="3" provided="true" name="Disabled Php 1" default_profile="0" language="php" enabled="true" PARENT_NAME="[null]"/>
- <rules_profiles id="4" provided="false" name="Disabled Php 2" default_profile="1" language="php" enabled="true" PARENT_NAME="[null]"/>
+ <rules_profiles id="3" version="1" used_profile="true" provided="true" name="Disabled Php 1" default_profile="0" language="php" enabled="true" PARENT_NAME="[null]"/>
+ <rules_profiles id="4" version="1" used_profile="true" provided="false" name="Disabled Php 2" default_profile="1" language="php" enabled="true" PARENT_NAME="[null]"/>
<!-- keep disabled -->
- <rules_profiles id="5" provided="true" name="Disabled Cobol" default_profile="1" language="cobol" enabled="false" PARENT_NAME="[null]"/>
+ <rules_profiles id="5" version="1" used_profile="true" provided="true" name="Disabled Cobol" default_profile="1" language="cobol" enabled="false" PARENT_NAME="[null]"/>
</dataset>
\ No newline at end of file
<dataset>
- <rules_profiles id="1" provided="true" name="Java 1" default_profile="0" language="java" enabled="true" PARENT_NAME="[null]"/>
- <rules_profiles id="2" provided="false" name="Java 2" default_profile="1" language="java" enabled="true" PARENT_NAME="[null]"/>
- <rules_profiles id="3" provided="true" name="Disabled Php 1" default_profile="0" language="php" enabled="false" PARENT_NAME="[null]"/>
- <rules_profiles id="4" provided="false" name="Disabled Php 2" default_profile="1" language="php" enabled="false" PARENT_NAME="[null]"/>
- <rules_profiles id="5" provided="true" name="Disabled Cobol" default_profile="1" language="cobol" enabled="false" PARENT_NAME="[null]"/>
+ <rules_profiles id="1" version="1" used_profile="true" provided="true" name="Java 1" default_profile="0" language="java" enabled="true" PARENT_NAME="[null]"/>
+ <rules_profiles id="2" version="1" used_profile="true" provided="false" name="Java 2" default_profile="1" language="java" enabled="true" PARENT_NAME="[null]"/>
+ <rules_profiles id="3" version="1" used_profile="true" provided="true" name="Disabled Php 1" default_profile="0" language="php" enabled="false" PARENT_NAME="[null]"/>
+ <rules_profiles id="4" version="1" used_profile="true" provided="false" name="Disabled Php 2" default_profile="1" language="php" enabled="false" PARENT_NAME="[null]"/>
+ <rules_profiles id="5" version="1" used_profile="true" provided="true" name="Disabled Cobol" default_profile="1" language="cobol" enabled="false" PARENT_NAME="[null]"/>
</dataset>
\ No newline at end of file
<metrics id="2" name="disabledkey2" val_type="INT" description="description" domain="domain"
short_name="name2" qualitative="false" user_managed="false" enabled="false" origin="JAV" worst_value="[null]" optimized_best_value="[null]" best_value="[null]" direction="1" hidden="false"/>
- <rules_profiles id="1" name="profile1" default_profile="true" provided="true" language="JAV" enabled="true"/>
- <rules_profiles id="2" name="profile2" default_profile="false" provided="false" language="JAV" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" name="profile1" default_profile="true" provided="true" language="JAV" enabled="true"/>
+ <rules_profiles id="2" version="1" used_profile="true" name="profile2" default_profile="false" provided="false" language="JAV" enabled="true"/>
<!-- ok -->
<alerts id="1" profile_id="1" metric_id="1" operator=">" value_error="30" value_warning="[null]"/>
short_name="name2" qualitative="false" user_managed="false" enabled="false" origin="JAV" worst_value="[null]" optimized_best_value="[null]" best_value="[null]" direction="1" hidden="false"/>
- <rules_profiles id="1" name="profile1" default_profile="true" provided="true" language="JAV" enabled="true"/>
- <rules_profiles id="2" name="profile2" default_profile="false" provided="false" language="JAV" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" name="profile1" default_profile="true" provided="true" language="JAV" enabled="true"/>
+ <rules_profiles id="2" version="1" used_profile="true" name="profile2" default_profile="false" provided="false" language="JAV" enabled="true"/>
<!-- ok -->
<alerts id="1" profile_id="1" metric_id="1" operator=">" value_error="30" value_warning="[null]"/>
<rules_parameters id="3" rule_id="1" name="param3" description="[null]" param_type="[null]"/>
- <rules_profiles id="1" name="profile name" language="java" default_profile="false" provided="false" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" name="profile name" language="java" default_profile="false" provided="false" enabled="true"/>
<active_rules id="1" rule_id="1" profile_id="1" failure_level="4" />
<active_rule_parameters id="1" active_rule_id="1" rules_parameter_id="1" value="one" />
<active_rule_parameters id="2" active_rule_id="1" rules_parameter_id="2" value="two" />
<rules_parameters id="1" rule_id="1" name="deprecated-prop" description="[null]" param_type="[null]"/>
- <rules_profiles id="1" name="sonar way" language="java" default_profile="false" provided="true" enabled="true"/>
+ <rules_profiles id="1" version="1" used_profile="true" name="sonar way" language="java" default_profile="false" provided="true" enabled="true"/>
<active_rules id="1" rule_id="1" profile_id="1" failure_level="4" />
<active_rules id="2" rule_id="2" profile_id="1" failure_level="0" />
primary key (id)
);
+create table ACTIVE_RULE_CHANGES (
+ ID INTEGER not null,
+ USER_LOGIN VARCHAR(40) not null,
+ PROFILE_ID INTEGER not null,
+ PROFILE_VERSION INTEGER not null,
+ RULE_ID INTEGER not null,
+ CHANGE_DATE TIMESTAMP not null,
+ ENABLED SMALLINT,
+ OLD_SEVERITY INTEGER,
+ NEW_SEVERITY INTEGER,
+ primary key (id)
+);
+CREATE INDEX ACTIVE_RULE_CHANGES_PID ON ACTIVE_RULE_CHANGES (PROFILE_ID);
+
create table ACTIVE_RULE_PARAMETERS (
ID INTEGER not null,
ACTIVE_RULE_ID INTEGER not null,
primary key (id)
);
+create table ACTIVE_RULE_PARAM_CHANGES (
+ ID INTEGER not null,
+ ACTIVE_RULE_CHANGE_ID INTEGER not null,
+ RULES_PARAMETER_ID INTEGER not null,
+ OLD_VALUE VARCHAR(4000),
+ NEW_VALUE VARCHAR(4000),
+ primary key (id)
+);
+CREATE INDEX ACTIVE_RULE_PARAM_CHANGES_CID ON ACTIVE_RULE_PARAM_CHANGES (ACTIVE_RULE_CHANGE_ID);
+
create table ALERTS (
ID INTEGER not null,
PROFILE_ID INTEGER,
LANGUAGE VARCHAR(16),
PARENT_NAME VARCHAR(100),
ENABLED SMALLINT,
+ VERSION INTEGER not null,
+ USED_PROFILE SMALLINT not null,
primary key (id)
);