aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2017-08-01 15:33:47 +0200
committerJanos Gyerik <janos.gyerik@sonarsource.com>2017-09-12 10:55:09 +0200
commitd3a6ef3150009d5828f1be984e372db8bf6ae80a (patch)
tree8fbb1fe1afd8b119310717b3702306a6d6350a3e
parent7ea28f815483178ae767ef556de4064d1bf121b0 (diff)
downloadsonarqube-d3a6ef3150009d5828f1be984e372db8bf6ae80a.tar.gz
sonarqube-d3a6ef3150009d5828f1be984e372db8bf6ae80a.zip
SONAR-9616 index the issues part of a non-main branch
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDto.java8
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueTesting.java5
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDbTester.java6
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java25
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueDoc.java22
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java27
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java33
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/UpdateConflictResolverTest.java6
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexerTest.java25
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTagsActionTest.java2
-rw-r--r--sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java8
12 files changed, 114 insertions, 55 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDto.java
index 2220fa71014..2dbc1c731aa 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDto.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDto.java
@@ -559,10 +559,6 @@ public final class IssueDto implements Serializable {
return this;
}
- /**
- * Can be null on Views or Devs
- */
- @CheckForNull
public String getProjectUuid() {
return projectUuid;
}
@@ -572,8 +568,8 @@ public final class IssueDto implements Serializable {
* <p/>
* Please use {@link #setProject(ComponentDto)} instead
*/
- public IssueDto setProjectUuid(@Nullable String s) {
- checkArgument(s == null || s.length() <= 50, "Value is too long for column ISSUES.PROJECT_UUID: %s", s);
+ public IssueDto setProjectUuid(String s) {
+ checkArgument(s.length() <= 50, "Value is too long for column ISSUES.PROJECT_UUID: %s", s);
this.projectUuid = s;
return this;
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueTesting.java b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueTesting.java
index 98ca360e510..32d524b67e0 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueTesting.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueTesting.java
@@ -22,6 +22,7 @@ package org.sonar.db.issue;
import java.util.Date;
import org.apache.commons.lang.math.RandomUtils;
import org.sonar.api.issue.Issue;
+import org.sonar.api.resources.Qualifiers;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.DateUtils;
@@ -30,6 +31,7 @@ import org.sonar.db.component.ComponentDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Sets.newHashSet;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
@@ -42,6 +44,9 @@ public class IssueTesting {
}
public static IssueDto newIssue(RuleDefinitionDto rule, ComponentDto project, ComponentDto file) {
+ checkArgument(project.qualifier().equals(Qualifiers.PROJECT));
+ checkArgument(file.projectUuid().equals(project.uuid()));
+
return new IssueDto()
.setKee("uuid_" + randomAlphabetic(5))
.setRule(rule)
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDbTester.java b/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDbTester.java
index 0c090b47871..bd7b3e0f9d7 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDbTester.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDbTester.java
@@ -75,9 +75,9 @@ public class IssueDbTester {
RuleDefinitionDto rule = db.rules().insert();
ComponentDto project = db.components().insertPrivateProject(organizationDto);
ComponentDto file = db.components().insertComponent(newFileDto(project));
- IssueDto issueDto = newIssue(rule, file, project);
- populateIssueDto.accept(issueDto);
- return insertIssue(issueDto);
+ IssueDto issue = newIssue(rule, project, file);
+ populateIssueDto.accept(issue);
+ return insertIssue(issue);
}
public IssueChangeDto insertChange(IssueChangeDto issueChangeDto) {
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java
index 2e196ac87a9..45d4daf52f3 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java
@@ -456,7 +456,7 @@ public class PurgeDaoTest {
assertThat(getComponentUuidsOfMeasures())
.containsOnly(view.uuid(), subview.uuid());
- underTest.deleteNonRootComponents(dbSession, asList(subview));
+ underTest.deleteNonRootComponents(dbSession, singletonList(subview));
assertThat(getComponentUuidsOfMeasures())
.containsOnly(view.uuid());
}
@@ -480,23 +480,6 @@ public class PurgeDaoTest {
}
@Test
- public void deleteNonRootComponents_deletes_issues_and_changes_of_any_non_root_component_of_a_view() {
- ComponentDto view = dbTester.components().insertView();
- ComponentDto subview = dbTester.components().insertComponent(ComponentTesting.newSubView(view));
- ComponentDto pc = dbTester.components().insertComponent(newProjectCopy("a", dbTester.components().insertPrivateProject(), view));
- insertIssueAndChangesFor(view, subview, pc);
- assertThat(getComponentUuidsOfIssueChanges()).containsOnly(view.uuid(), subview.uuid(), pc.uuid());
-
- underTest.deleteNonRootComponents(dbSession, singletonList(pc));
- assertThat(getComponentUuidsOfIssueChanges())
- .containsOnly(view.uuid(), subview.uuid());
-
- underTest.deleteNonRootComponents(dbSession, asList(subview));
- assertThat(getComponentUuidsOfIssueChanges())
- .containsOnly(view.uuid());
- }
-
- @Test
public void deleteNonRootComponents_deletes_file_sources_of_file_component_of_a_project_only() {
ComponentDto project = new Random().nextBoolean() ? dbTester.components().insertPublicProject() : dbTester.components().insertPrivateProject();
ComponentDto module1 = dbTester.components().insertComponent(ComponentTesting.newModuleDto(project));
@@ -669,9 +652,9 @@ public class PurgeDaoTest {
.map(row -> (String) row.get("COMPONENT_UUID"));
}
- private void insertIssueAndChangesFor(ComponentDto... components) {
- Arrays.stream(components).forEach(componentDto -> {
- IssueDto issue = dbTester.issues().insert(RuleTesting.newRule(), componentDto, componentDto);
+ private void insertIssueAndChangesFor(ComponentDto project, ComponentDto... otherComponents) {
+ Stream.concat(Stream.of(project), Arrays.stream(otherComponents)).forEach(componentDto -> {
+ IssueDto issue = dbTester.issues().insert(RuleTesting.newRule(), project, componentDto);
dbTester.issues().insertComment(issue, "foo", "bar");
});
dbSession.commit();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueDoc.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueDoc.java
index eef37179e5b..8fc5c0d7d15 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueDoc.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueDoc.java
@@ -38,7 +38,7 @@ public class IssueDoc extends BaseDoc {
}
public IssueDoc() {
- super(Maps.newHashMapWithExpectedSize(30));
+ super(Maps.newHashMapWithExpectedSize(32));
}
@Override
@@ -77,6 +77,14 @@ public class IssueDoc extends BaseDoc {
return getField(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID);
}
+ public String branchUuid() {
+ return getField(IssueIndexDefinition.FIELD_ISSUE_BRANCH_UUID);
+ }
+
+ public boolean isMainBranch() {
+ return getField(IssueIndexDefinition.FIELD_ISSUE_IS_MAIN_BRANCH);
+ }
+
public RuleKey ruleKey() {
return RuleKey.parse(getField(IssueIndexDefinition.FIELD_ISSUE_RULE_KEY));
}
@@ -172,11 +180,21 @@ public class IssueDoc extends BaseDoc {
return this;
}
- public IssueDoc setProjectUuid(@Nullable String s) {
+ public IssueDoc setProjectUuid(String s) {
setField(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, s);
return this;
}
+ public IssueDoc setBranchUuid(String s) {
+ setField(IssueIndexDefinition.FIELD_ISSUE_BRANCH_UUID, s);
+ return this;
+ }
+
+ public IssueDoc setIsMainBranch(boolean b) {
+ setField(IssueIndexDefinition.FIELD_ISSUE_IS_MAIN_BRANCH, b);
+ return this;
+ }
+
public IssueDoc setRuleKey(@Nullable String s) {
setField(IssueIndexDefinition.FIELD_ISSUE_RULE_KEY, s);
return this;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java
index 0eabde4223c..e127d99c2f0 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java
@@ -58,7 +58,32 @@ public class IssueIndexDefinition implements IndexDefinition {
public static final String FIELD_ISSUE_MODULE_UUID = "module";
public static final String FIELD_ISSUE_MODULE_PATH = "modulePath";
public static final String FIELD_ISSUE_ORGANIZATION_UUID = "organization";
+
+ /**
+ * The (real) project, equivalent of projects.main_branch_project_uuid | projects.project_uuid, so
+ * it's never empty.
+ * On main branches, it is the UUID of the project.
+ * On non-main branches, it is the UUID of the main branch (which represents the project).
+ * This field maps the parent association with issues/authorization.
+ */
public static final String FIELD_ISSUE_PROJECT_UUID = "project";
+
+ /**
+ * The branch, as represented by the component with TRK qualifier. It's never
+ * empty. It maps the DB column projects.project_uuid:
+ * - on main branches, it is the UUID of the project. It equals {@link #FIELD_ISSUE_PROJECT_UUID}.
+ * - on non-main branches, it is the UUID of the project representing the branch and it
+ * is different than {@link #FIELD_ISSUE_PROJECT_UUID}.
+ */
+ public static final String FIELD_ISSUE_BRANCH_UUID = "branch";
+
+ /**
+ * Whether component is in a main branch or not.
+ * If true, then {@link #FIELD_ISSUE_BRANCH_UUID} equals {@link #FIELD_ISSUE_PROJECT_UUID}.
+ * If false, then {@link #FIELD_ISSUE_BRANCH_UUID} is different than {@link #FIELD_ISSUE_PROJECT_UUID}.
+ */
+ public static final String FIELD_ISSUE_IS_MAIN_BRANCH = "isMainBranch";
+
public static final String FIELD_ISSUE_DIRECTORY_PATH = "dirPath";
public static final String FIELD_ISSUE_RESOLUTION = "resolution";
public static final String FIELD_ISSUE_RULE_KEY = "ruleKey";
@@ -117,6 +142,8 @@ public class IssueIndexDefinition implements IndexDefinition {
type.createUuidPathField(FIELD_ISSUE_MODULE_PATH);
type.keywordFieldBuilder(FIELD_ISSUE_ORGANIZATION_UUID).disableNorms().build();
type.keywordFieldBuilder(FIELD_ISSUE_PROJECT_UUID).disableNorms().addSubFields(SORTABLE_ANALYZER).build();
+ type.keywordFieldBuilder(FIELD_ISSUE_BRANCH_UUID).disableNorms().build();
+ type.createBooleanField(FIELD_ISSUE_IS_MAIN_BRANCH);
type.keywordFieldBuilder(FIELD_ISSUE_DIRECTORY_PATH).disableNorms().build();
type.keywordFieldBuilder(FIELD_ISSUE_RESOLUTION).disableNorms().build();
type.keywordFieldBuilder(FIELD_ISSUE_RULE_KEY).disableNorms().build();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java
index a939bfac5a1..6a72a75c264 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java
@@ -69,23 +69,24 @@ class IssueIteratorForSingleChunk implements IssueIterator {
"r.plugin_name",
"r.plugin_rule_key",
"r.language",
- "p.uuid",
- "p.module_uuid_path",
- "p.path",
- "p.scope",
- "p.organization_uuid",
- "p.project_uuid",
+ "c.uuid",
+ "c.module_uuid_path",
+ "c.path",
+ "c.scope",
+ "c.organization_uuid",
+ "c.project_uuid",
// column 21
+ "c.main_branch_project_uuid",
"i.tags",
"i.issue_type"
};
private static final String SQL_ALL = "select " + StringUtils.join(FIELDS, ",") + " from issues i " +
"inner join rules r on r.id = i.rule_id " +
- "inner join projects p on p.uuid = i.component_uuid ";
+ "inner join projects c on c.uuid = i.component_uuid ";
- private static final String PROJECT_FILTER = " and p.project_uuid=?";
+ private static final String PROJECT_FILTER = " and c.project_uuid = ?";
private static final String ISSUE_KEY_FILTER_PREFIX = " and i.kee in (";
private static final String ISSUE_KEY_FILTER_SUFFIX = ")";
@@ -212,11 +213,19 @@ class IssueIteratorForSingleChunk implements IssueIterator {
doc.setFilePath(filePath);
doc.setDirectoryPath(extractDirPath(doc.filePath(), scope));
doc.setOrganizationUuid(rs.getString(19));
- String projectUuid = rs.getString(20);
- doc.setProjectUuid(projectUuid);
- String tags = rs.getString(21);
+ String branchUuid = rs.getString(20);
+ String mainBranchProjectUuid = DatabaseUtils.getString(rs, 21);
+ doc.setBranchUuid(branchUuid);
+ if (mainBranchProjectUuid == null) {
+ doc.setProjectUuid(branchUuid);
+ doc.setIsMainBranch(true);
+ } else {
+ doc.setProjectUuid(mainBranchProjectUuid);
+ doc.setIsMainBranch(false);
+ }
+ String tags = rs.getString(22);
doc.setTags(ImmutableList.copyOf(IssueIteratorForSingleChunk.TAGS_SPLITTER.split(tags == null ? "" : tags)));
- doc.setType(RuleType.valueOf(rs.getInt(22)));
+ doc.setType(RuleType.valueOf(rs.getInt(23)));
return doc;
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java b/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java
index 95f4ce1105d..e28ad1cc35a 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java
@@ -164,7 +164,7 @@ public class RuleDoc extends BaseDoc {
}
public boolean isTemplate() {
- return (Boolean) getField(RuleIndexDefinition.FIELD_RULE_IS_TEMPLATE);
+ return getField(RuleIndexDefinition.FIELD_RULE_IS_TEMPLATE);
}
public RuleDoc setIsTemplate(@Nullable Boolean b) {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/UpdateConflictResolverTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/UpdateConflictResolverTest.java
index a67e1da58b5..662b3f84e8c 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/UpdateConflictResolverTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/UpdateConflictResolverTest.java
@@ -43,7 +43,8 @@ public class UpdateConflictResolverTest {
.setKey("ABCDE")
.setType(RuleType.CODE_SMELL)
.setRuleKey(RuleKey.of("squid", "AvoidCycles"))
- .setComponentKey("struts:org.apache.struts.Action")
+ .setProjectUuid("U1")
+ .setComponentUuid("U2")
.setNew(false)
.setStatus(Issue.STATUS_OPEN);
@@ -55,7 +56,8 @@ public class UpdateConflictResolverTest {
.setType(RuleType.CODE_SMELL)
.setRuleId(10)
.setRuleKey("squid", "AvoidCycles")
- .setComponentKey("struts:org.apache.struts.Action")
+ .setProjectUuid("U1")
+ .setComponentUuid("U2")
.setLine(10)
.setStatus(Issue.STATUS_OPEN)
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexerTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexerTest.java
index 0954b7dba43..dd42cc7e85e 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexerTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexerTest.java
@@ -120,7 +120,10 @@ public class IssueIndexerTest {
assertThat(doc.organizationUuid()).isEqualTo(organization.getUuid());
assertThat(doc.assignee()).isEqualTo(issue.getAssignee());
assertThat(doc.authorLogin()).isEqualTo(issue.getAuthorLogin());
- assertThat(doc.componentUuid()).isEqualTo(issue.getComponentUuid());
+ assertThat(doc.componentUuid()).isEqualTo(file.uuid());
+ assertThat(doc.projectUuid()).isEqualTo(project.uuid());
+ assertThat(doc.branchUuid()).isEqualTo(project.uuid());
+ assertThat(doc.isMainBranch()).isTrue();
assertThat(doc.closeDate()).isEqualTo(issue.getIssueCloseDate());
assertThat(doc.creationDate()).isEqualToIgnoringMillis(issue.getIssueCreationDate());
assertThat(doc.directoryPath()).isEqualTo(dir.path());
@@ -445,6 +448,26 @@ public class IssueIndexerTest {
assertThat(es.countDocuments(INDEX_TYPE_ISSUE)).isEqualTo(1L);
}
+ @Test
+ public void index_issue_in_non_main_branch() {
+ RuleDefinitionDto rule = db.rules().insert();
+ ComponentDto project = db.components().insertPrivateProject(organization);
+ ComponentDto branch = db.components().insertProjectBranch(project, "feature/foo");
+ ComponentDto dir = db.components().insertComponent(ComponentTesting.newDirectory(branch, "src/main/java/foo"));
+ ComponentDto file = db.components().insertComponent(newFileDto(branch, dir, "F1"));
+ IssueDto issue = db.issues().insertIssue(IssueTesting.newIssue(rule, branch, file));
+
+ underTest.indexOnStartup(emptySet());
+
+ IssueDoc doc = es.getDocuments(INDEX_TYPE_ISSUE, IssueDoc.class).get(0);
+ assertThat(doc.getId()).isEqualTo(issue.getKey());
+ assertThat(doc.organizationUuid()).isEqualTo(organization.getUuid());
+ assertThat(doc.componentUuid()).isEqualTo(file.uuid());
+ assertThat(doc.projectUuid()).isEqualTo(project.uuid());
+ assertThat(doc.branchUuid()).isEqualTo(branch.uuid());
+ assertThat(doc.isMainBranch()).isFalse();
+ }
+
private void addIssueToIndex(String projectUuid, String issueKey) {
es.putDocuments(INDEX_TYPE_ISSUE,
newDoc().setKey(issueKey).setProjectUuid(projectUuid));
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTagsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTagsActionTest.java
index 614b3e90f0d..f1fb31543c2 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTagsActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTagsActionTest.java
@@ -236,7 +236,7 @@ public class SetTagsActionTest {
RuleDefinitionDto rule = db.rules().insert();
ComponentDto project = db.components().insertPublicProject();
ComponentDto file = db.components().insertComponent(newFileDto(project));
- return IssueTesting.newIssue(rule, file, project);
+ return IssueTesting.newIssue(rule, project, file);
}
private void logIn(IssueDto issueDto) {
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java
index e397f7dfe7d..a92b911d44f 100644
--- a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java
+++ b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java
@@ -178,17 +178,13 @@ public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure.
return this;
}
- /**
- * Can be null on Views
- */
@Override
- @CheckForNull
public String projectUuid() {
return projectUuid;
}
- public DefaultIssue setProjectUuid(@Nullable String projectUuid) {
- this.projectUuid = projectUuid;
+ public DefaultIssue setProjectUuid(String s) {
+ this.projectUuid = s;
return this;
}