diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-04-18 12:15:13 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-04-18 14:09:18 +0200 |
commit | bfeca720d3a702b77664b0164aa02ce89b353cec (patch) | |
tree | e68bad3f6151ed92c89667fa7e92e55cc8487401 /sonar-core/src | |
parent | 5857333fb71af4090a6b3dcb3e972d465873f98d (diff) | |
download | sonarqube-bfeca720d3a702b77664b0164aa02ce89b353cec.tar.gz sonarqube-bfeca720d3a702b77664b0164aa02ce89b353cec.zip |
SONAR-5218 Once a module has been turned into a project, its issues are no more visible in the UI
Diffstat (limited to 'sonar-core/src')
13 files changed, 228 insertions, 12 deletions
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java index 68284cb07ce..859ad804ad2 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java @@ -35,6 +35,7 @@ import java.util.UUID; public class DefaultIssueBuilder implements Issuable.IssueBuilder { private String componentKey; + private String projectKey; private RuleKey ruleKey; private Integer line; private String message; @@ -52,6 +53,12 @@ public class DefaultIssueBuilder implements Issuable.IssueBuilder { return this; } + + public DefaultIssueBuilder projectKey(String projectKey) { + this.projectKey = projectKey; + return this; + } + @Override public Issuable.IssueBuilder ruleKey(RuleKey ruleKey) { this.ruleKey = ruleKey; @@ -99,6 +106,7 @@ public class DefaultIssueBuilder implements Issuable.IssueBuilder { @Override public DefaultIssue build() { + Preconditions.checkNotNull(projectKey, "Project key must be set"); Preconditions.checkNotNull(componentKey, "Component key must be set"); Preconditions.checkNotNull(ruleKey, "Rule key must be set"); @@ -107,6 +115,7 @@ public class DefaultIssueBuilder implements Issuable.IssueBuilder { Preconditions.checkState(!Strings.isNullOrEmpty(key), "Fail to generate issue key"); issue.setKey(key); issue.setComponentKey(componentKey); + issue.setProjectKey(projectKey); issue.setRuleKey(ruleKey); issue.setMessage(message); issue.setSeverity(severity); diff --git a/sonar-core/src/main/java/org/sonar/core/issue/IssueUpdater.java b/sonar-core/src/main/java/org/sonar/core/issue/IssueUpdater.java index cdd3717f699..9ac381eeffd 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/IssueUpdater.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/IssueUpdater.java @@ -247,4 +247,20 @@ public class IssueUpdater implements BatchComponent, ServerComponent { return false; } + public boolean setProject(DefaultIssue issue, String key, IssueChangeContext context) { + if (!Objects.equal(key, issue.projectKey())) { + issue.setProjectKey(key); + issue.setUpdateDate(context.date()); + issue.setChanged(true); + return true; + } + return false; + } + + public boolean setPastProject(DefaultIssue issue, String previousKey, IssueChangeContext context) { + String currentProjectKey = issue.projectKey(); + issue.setProjectKey(previousKey); + return setProject(issue, currentProjectKey, context); + } + } diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java index 3b7aa30ccc4..be0d275f1cd 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java @@ -390,7 +390,7 @@ public final class IssueDto implements Serializable { .setUpdatedAt(now); } - public static IssueDto toDtoForUpdate(DefaultIssue issue, Date now) { + public static IssueDto toDtoForUpdate(DefaultIssue issue, Long rootComponentId, Date now) { // Invariant fields, like key and rule, can't be updated return new IssueDto() .setKee(issue.key()) @@ -408,6 +408,7 @@ public final class IssueDto implements Serializable { .setActionPlanKey(issue.actionPlanKey()) .setIssueAttributes(KeyValueFormat.format(issue.attributes())) .setAuthorLogin(issue.authorLogin()) + .setRootComponentId(rootComponentId) .setIssueCreationDate(issue.creationDate()) .setIssueCloseDate(issue.closeDate()) .setIssueUpdateDate(issue.updateDate()) diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueMapper.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueMapper.java index 3c3a8784891..600b5e4f8c2 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueMapper.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueMapper.java @@ -31,8 +31,6 @@ public interface IssueMapper { IssueDto selectByKey(String key); - List<IssueDto> selectNonClosedIssuesByModule(int rootComponentId); - /** * Return a paginated list of authorized issue ids for a user. * If the role is null, then the authorisation check is disabled. diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueStorage.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueStorage.java index fad9862d7be..a52f728a5df 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueStorage.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueStorage.java @@ -119,7 +119,7 @@ public abstract class IssueStorage { } private void update(IssueMapper issueMapper, Date now, DefaultIssue issue) { - IssueDto dto = IssueDto.toDtoForUpdate(issue, now); + IssueDto dto = IssueDto.toDtoForUpdate(issue, projectId(issue), now); if (Issue.STATUS_CLOSED.equals(issue.status()) || issue.selectedAt() == null) { // Issue is closed by scan or changed by end-user issueMapper.update(dto); diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/UpdateConflictResolver.java b/sonar-core/src/main/java/org/sonar/core/issue/db/UpdateConflictResolver.java index 536667cae3f..73370a7face 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/db/UpdateConflictResolver.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/UpdateConflictResolver.java @@ -41,7 +41,7 @@ class UpdateConflictResolver { IssueDto dbIssue = mapper.selectByKey(issue.key()); if (dbIssue != null) { mergeFields(dbIssue, issue); - mapper.update(IssueDto.toDtoForUpdate(issue, new Date())); + mapper.update(IssueDto.toDtoForUpdate(issue, dbIssue.getRootComponentId(), new Date())); } } diff --git a/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml b/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml index a3e15378041..bd85afc9313 100644 --- a/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml @@ -89,6 +89,7 @@ reporter=#{reporter}, assignee=#{assignee}, author_login=#{authorLogin}, + root_component_id=#{rootComponentId}, issue_attributes=#{issueAttributes}, issue_creation_date=#{issueCreationDate}, issue_update_date=#{issueUpdateDate}, @@ -115,6 +116,7 @@ reporter=#{reporter}, assignee=#{assignee}, author_login=#{authorLogin}, + root_component_id=#{rootComponentId}, issue_attributes=#{issueAttributes}, issue_creation_date=#{issueCreationDate}, issue_update_date=#{issueUpdateDate}, @@ -163,10 +165,12 @@ i.updated_at as updatedAt, r.plugin_rule_key as ruleKey, r.plugin_name as ruleRepo, - p.kee as componentKey + p.kee as componentKey, + root.kee as rootComponentKey from issues i - inner join rules r on r.id=i.rule_id inner join (select p.id,p.kee from projects p where (p.root_id=#{id} and p.qualifier <> 'BRC') or (p.id=#{id})) p on p.id=i.component_id + inner join rules r on r.id=i.rule_id + left outer join projects root on root.id=i.root_component_id <where> and i.status <> 'CLOSED' </where> diff --git a/sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueBuilderTest.java b/sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueBuilderTest.java index 916be3ea6e1..30b34609c00 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueBuilderTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueBuilderTest.java @@ -32,8 +32,10 @@ public class DefaultIssueBuilderTest { @Test public void build_new_issue() throws Exception { String componentKey = "org.apache.struts:struts-core:Action.java"; + String projectKey = "org.apache.struts"; DefaultIssue issue = (DefaultIssue) new DefaultIssueBuilder() .componentKey(componentKey) + .projectKey(projectKey) .message("the message") .line(123) .effortToFix(10000.0) @@ -47,6 +49,7 @@ public class DefaultIssueBuilderTest { assertThat(issue.key()).isNotNull(); assertThat(issue.effortToFix()).isEqualTo(10000.0); assertThat(issue.componentKey()).isEqualTo(componentKey); + assertThat(issue.projectKey()).isEqualTo(projectKey); assertThat(issue.message()).isEqualTo("the message"); assertThat(issue.line()).isEqualTo(123); assertThat(issue.ruleKey().repository()).isEqualTo("squid"); @@ -65,6 +68,7 @@ public class DefaultIssueBuilderTest { public void not_set_default_severity() { DefaultIssue issue = (DefaultIssue) new DefaultIssueBuilder() .componentKey("Action.java") + .projectKey("org.apache.struts") .ruleKey(RuleKey.of("squid", "NullDereference")) .build(); diff --git a/sonar-core/src/test/java/org/sonar/core/issue/IssueUpdaterTest.java b/sonar-core/src/test/java/org/sonar/core/issue/IssueUpdaterTest.java index c0dfa62ec32..5373ebef6eb 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/IssueUpdaterTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/IssueUpdaterTest.java @@ -447,4 +447,35 @@ public class IssueUpdaterTest { assertThat(issue.mustSendNotifications()).isFalse(); } + @Test + public void set_project() throws Exception { + boolean updated = updater.setProject(issue, "sample", context); + assertThat(updated).isTrue(); + assertThat(issue.projectKey()).isEqualTo("sample"); + + // do not save change + assertThat(issue.currentChange()).isNull(); + assertThat(issue.mustSendNotifications()).isFalse(); + } + + @Test + public void set_past_project() throws Exception { + issue.setProjectKey("new project key"); + boolean updated = updater.setPastProject(issue, "past project key", context); + assertThat(updated).isTrue(); + assertThat(issue.projectKey()).isEqualTo("new project key"); + + // do not save change + assertThat(issue.currentChange()).isNull(); + assertThat(issue.mustSendNotifications()).isFalse(); + } + + @Test + public void not_set_past_project_if_no_change() throws Exception { + issue.setProjectKey("key"); + boolean updated = updater.setPastProject(issue, "key", context); + assertThat(updated).isFalse(); + assertThat(issue.projectKey()).isEqualTo("key"); + } + } diff --git a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDaoTest.java b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDaoTest.java index a8087a3d4d8..45790762a26 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDaoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDaoTest.java @@ -310,7 +310,7 @@ public class IssueDaoTest extends AbstractDaoTestCase { } @Test - public void should_select_non_closed_issues_by_module() { + public void select_non_closed_issues_by_module() { setupData("shared", "should_select_non_closed_issues_by_module"); // 400 is a non-root module, we should find 2 issues from classes and one on itself @@ -322,11 +322,37 @@ public class IssueDaoTest extends AbstractDaoTestCase { assertThat(issue.getRuleRepo()).isNotNull(); assertThat(issue.getRule()).isNotNull(); assertThat(issue.getComponentKey()).isNotNull(); + assertThat(issue.getRootComponentKey()).isEqualTo("struts"); // 399 is the root module, we should only find 1 issue on itself handler = new DefaultResultHandler(); dao.selectNonClosedIssuesByModule(399, handler); assertThat(handler.getResultList()).hasSize(1); + + issue = (IssueDto) handler.getResultList().get(0); + assertThat(issue.getComponentKey()).isEqualTo("struts"); + assertThat(issue.getRootComponentKey()).isEqualTo("struts"); + } + + /** + * SONAR-5218 + */ + @Test + public void select_non_closed_issues_by_module_on_removed_project() { + // All issues are linked on a project that is not existing anymore + + setupData("shared", "should_select_non_closed_issues_by_module_on_removed_project"); + + // 400 is a non-root module, we should find 2 issues from classes and one on itself + DefaultResultHandler handler = new DefaultResultHandler(); + dao.selectNonClosedIssuesByModule(400, handler); + assertThat(handler.getResultList()).hasSize(3); + + IssueDto issue = (IssueDto) handler.getResultList().get(0); + assertThat(issue.getRuleRepo()).isNotNull(); + assertThat(issue.getRule()).isNotNull(); + assertThat(issue.getComponentKey()).isNotNull(); + assertThat(issue.getRootComponentKey()).isNull(); } @Test diff --git a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueMapperTest.java b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueMapperTest.java index e3e074562ee..705c5358ea8 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueMapperTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueMapperTest.java @@ -84,7 +84,7 @@ public class IssueMapperTest extends AbstractDaoTestCase { IssueDto dto = new IssueDto(); dto.setComponentId(123l); - dto.setRootComponentId(100l); + dto.setRootComponentId(101l); dto.setRuleId(200); dto.setKee("ABCDE"); dto.setLine(500); @@ -119,7 +119,7 @@ public class IssueMapperTest extends AbstractDaoTestCase { IssueDto dto = new IssueDto(); dto.setComponentId(123l); - dto.setRootComponentId(100l); + dto.setRootComponentId(101l); dto.setRuleId(200); dto.setKee("ABCDE"); dto.setLine(500); @@ -157,7 +157,7 @@ public class IssueMapperTest extends AbstractDaoTestCase { IssueDto dto = new IssueDto(); dto.setComponentId(123l); - dto.setRootComponentId(100l); + dto.setRootComponentId(101l); dto.setRuleId(200); dto.setKee("ABCDE"); dto.setLine(500); diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_non_closed_issues_by_module_on_removed_project.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_non_closed_issues_by_module_on_removed_project.xml new file mode 100644 index 00000000000..ec2c35e66d9 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_non_closed_issues_by_module_on_removed_project.xml @@ -0,0 +1,127 @@ +<!-- + ~ SonarQube, open source software quality management tool. + ~ Copyright (C) 2008-2014 SonarSource + ~ mailto:contact AT sonarsource DOT com + ~ + ~ SonarQube is free software; you can redistribute it and/or + ~ modify it under the terms of the GNU Lesser General Public + ~ License as published by the Free Software Foundation; either + ~ version 3 of the License, or (at your option) any later version. + ~ + ~ SonarQube is distributed in the hope that it will be useful, + ~ but WITHOUT ANY WARRANTY; without even the implied warranty of + ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + ~ Lesser General Public License for more details. + ~ + ~ You should have received a copy of the GNU Lesser General Public License + ~ along with this program; if not, write to the Free Software Foundation, + ~ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + --> + +<dataset> + + <!-- Open Issue on a file --> + <issues + id="100" + kee="100" + component_id="401" + root_component_id="111" + rule_id="500" + severity="BLOCKER" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="[null]" + status="OPEN" + resolution="[null]" + checksum="[null]" + reporter="user" + assignee="user" + author_login="[null]" + issue_attributes="[null]" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-16" + updated_at="[null]" + /> + + <!-- Open Issue on a file --> + <issues + id="101" + kee="101" + component_id="402" + root_component_id="111" + rule_id="501" + severity="MAJOR" + manual_severity="[false]" + message="[null]" + line="120" + effort_to_fix="[null]" + status="OPEN" + resolution="[null]" + checksum="[null]" + reporter="[null]" + assignee="user" + author_login="[null]" + issue_attributes="[null]" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-10" + updated_at="[null]" + /> + + <!-- Closed Issue on a file --> + <issues + id="102" + kee="102" + component_id="402" + root_component_id="111" + rule_id="501" + severity="MAJOR" + manual_severity="[false]" + message="[null]" + line="120" + effort_to_fix="[null]" + status="CLOSED" + resolution="FIXED" + checksum="[null]" + reporter="[null]" + assignee="user" + author_login="[null]" + issue_attributes="[null]" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-10" + updated_at="[null]" + /> + + <!-- Open Issue on a sub module --> + <issues + id="103" + kee="103" + component_id="400" + root_component_id="111" + rule_id="501" + severity="MAJOR" + manual_severity="[false]" + message="[null]" + line="[null]" + effort_to_fix="[null]" + status="OPEN" + resolution="[null]" + checksum="[null]" + reporter="[null]" + assignee="user" + author_login="[null]" + issue_attributes="[null]" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-10" + updated_at="[null]" + /> + +</dataset> diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueMapperTest/testUpdate-result.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueMapperTest/testUpdate-result.xml index 8016cfac576..a923dfa54e0 100644 --- a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueMapperTest/testUpdate-result.xml +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueMapperTest/testUpdate-result.xml @@ -3,7 +3,7 @@ id="100" kee="ABCDE" component_id="123" - root_component_id="100" + root_component_id="101" rule_id="200" severity="BLOCKER" manual_severity="[false]" |