import org.sonar.api.issue.internal.FieldDiffs;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
+import org.sonar.core.persistence.BatchSession;
import org.sonar.core.persistence.MyBatis;
import java.util.Arrays;
import java.util.Date;
+/**
+ * Save issues into database. It is executed :
+ * <ul>
+ * <li>once at the end of scan, even on multi-module projects</li>
+ * <li>on each server-side action initiated by UI or web service</li>
+ * </ul>
+ *
+ * @since 3.6
+ */
public abstract class IssueStorage {
private final MyBatis mybatis;
}
public void save(Iterable<DefaultIssue> issues) {
+ // Batch session can not be used. It does not return the number of updated rows,
+ // required for detecting conflicts.
SqlSession session = mybatis.openSession();
+ int count = 0;
IssueMapper issueMapper = session.getMapper(IssueMapper.class);
IssueChangeMapper issueChangeMapper = session.getMapper(IssueChangeMapper.class);
Date now = new Date();
update(issueMapper, now, issue);
}
insertChanges(issueChangeMapper, issue);
-
+ if (count++> BatchSession.MAX_BATCH_SIZE) {
+ session.commit();
+ }
}
session.commit();
} finally {
checkTables("should_update_issues", new String[]{"id", "created_at", "updated_at"}, "issues", "issue_changes");
}
+ @Test
+ public void should_resolve_conflicts_on_updates() throws Exception {
+ setupData("should_resolve_conflicts_on_updates");
+
+ FakeSaver saver = new FakeSaver(getMyBatis(), new FakeRuleFinder());
+
+ Date date = DateUtils.parseDate("2013-05-18");
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("ABCDE")
+ .setNew(false)
+ .setChanged(true)
+ .setCreationDate(DateUtils.parseDate("2005-05-12"))
+ .setUpdateDate(date)
+ .setRuleKey(RuleKey.of("squid", "AvoidCycles"))
+ .setComponentKey("struts:Action")
+
+ // issue in database has been updated in 2013, after the loading by scan
+ .setSelectedAt(DateUtils.parseDate("2005-01-01"))
+
+ // fields to be updated
+ .setLine(444)
+ .setSeverity("BLOCKER")
+ .setChecksum("FFFFF")
+
+ // fields overridden by end-user -> do not save
+ .setAssignee("looser")
+ .setResolution(null)
+ .setStatus("REOPEN");
+
+ saver.save(issue);
+
+ checkTables("should_resolve_conflicts_on_updates", new String[]{"id", "created_at", "updated_at"}, "issues");
+ }
+
static class FakeSaver extends IssueStorage {
protected FakeSaver(MyBatis mybatis, RuleFinder ruleFinder) {
super(mybatis, ruleFinder);
--- /dev/null
+<!--
+ ~ SonarQube, open source software quality management tool.
+ ~ Copyright (C) 2008-2013 SonarSource
+ ~ mailto:contact AT sonarsource DOT com
+ ~
+ ~ SonarQube is free software; you can redistribute it and/or
+ ~ modify it under the terms of the GNU Lesser General Public
+ ~ License as published by the Free Software Foundation; either
+ ~ version 3 of the License, or (at your option) any later version.
+ ~
+ ~ SonarQube is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this program; if not, write to the Free Software Foundation,
+ ~ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ -->
+<dataset>
+ <rules id="200" name="Avoid Cycles" plugin_rule_key="AvoidCycles"
+ plugin_config_key="[null]" plugin_name="squid"/>
+
+ <projects id="10" scope="PRJ" qualifier="TRK" kee="struts" name="Struts"/>
+ <projects id="100" scope="FIL" qualifier="CLA" kee="struts:Action" name="Action"/>
+
+ <issues id="1"
+ kee="ABCDE"
+ resolution="FIXED"
+ status="RESOLVED"
+ severity="BLOCKER"
+ manual_severity="[false]"
+ assignee="winner"
+ author_login="[null]"
+ checksum="FFFFF"
+ effort_to_fix="[null]"
+ message="[null]"
+ line="444"
+ component_id="100"
+ root_component_id="10"
+ rule_id="200"
+ reporter="[null]"
+ issue_attributes=""
+ action_plan_key="[null]"
+ created_at="2005-05-12"
+ updated_at="2013-05-18"
+ issue_creation_date="2005-05-12 00:00:00.0"
+ issue_update_date="2013-05-18 00:00:00.0"
+ issue_close_date="[null]"
+ />
+</dataset>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ SonarQube, open source software quality management tool.
+ ~ Copyright (C) 2008-2013 SonarSource
+ ~ mailto:contact AT sonarsource DOT com
+ ~
+ ~ SonarQube is free software; you can redistribute it and/or
+ ~ modify it under the terms of the GNU Lesser General Public
+ ~ License as published by the Free Software Foundation; either
+ ~ version 3 of the License, or (at your option) any later version.
+ ~
+ ~ SonarQube is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this program; if not, write to the Free Software Foundation,
+ ~ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ -->
+<dataset>
+
+ <rules id="200" name="Avoid Cycles" plugin_rule_key="AvoidCycles"
+ plugin_config_key="[null]" plugin_name="squid" />
+
+ <projects id="10" scope="PRJ" qualifier="TRK" kee="struts" name="Struts"/>
+ <projects id="100" scope="FIL" qualifier="CLA" kee="struts:Action" name="Action"/>
+
+
+ <issues id="1"
+ kee="ABCDE"
+ assignee="winner"
+ resolution="FIXED"
+ status="RESOLVED"
+ severity="MAJOR"
+ manual_severity="[false]"
+ author_login="[null]"
+ checksum="FFFFF"
+ effort_to_fix="[null]"
+ message="[null]"
+ line="1"
+ component_id="100"
+ root_component_id="10"
+ rule_id="200"
+ reporter="[null]"
+ issue_attributes=""
+ action_plan_key="[null]"
+ created_at="2005-05-12"
+ updated_at="2013-05-18"
+ issue_creation_date="2005-05-12 00:00:00.0"
+ issue_update_date="2013-05-18 00:00:00.0"
+ issue_close_date="[null]"
+ />
+</dataset>
\ No newline at end of file
return selectedAt;
}
- public void setSelectedAt(@Nullable Date d) {
+ public DefaultIssue setSelectedAt(@Nullable Date d) {
this.selectedAt = d;
+ return this;
}
@Override