]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9616 Handle branch in batch/issues
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 3 Aug 2017 13:41:24 +0000 (15:41 +0200)
committerJanos Gyerik <janos.gyerik@sonarsource.com>
Tue, 12 Sep 2017 08:55:10 +0000 (10:55 +0200)
20 files changed:
server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDto.java
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDto.java
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml
server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDbTester.java
server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDtoTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentTesting.java
server/sonar-db-dao/src/test/java/org/sonar/db/measure/ProjectMeasuresIndexerIteratorTest.java
server/sonar-server/src/main/java/org/sonar/server/batch/IssuesAction.java
server/sonar-server/src/main/java/org/sonar/server/component/ComponentFinder.java
server/sonar-server/src/main/java/org/sonar/server/ws/KeyExamples.java
server/sonar-server/src/test/java/org/sonar/server/batch/IssuesActionTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ComponentFinderTest.java
server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexerTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexerTest.java
server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexerTest.java
server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java
server/sonar-server/src/test/java/org/sonar/server/user/ServerUserSessionTest.java

index f3a71679f553814a1337fe8f8138989d28462e3e..387d91d0ae16358374fe0aee15e8d3cf5e2a3765 100644 (file)
@@ -97,16 +97,18 @@ public class BranchDto {
     return uuid;
   }
 
-  public void setUuid(String s) {
+  public BranchDto setUuid(String s) {
     this.uuid = s;
+    return this;
   }
 
   public String getProjectUuid() {
     return projectUuid;
   }
 
-  public void setProjectUuid(String s) {
+  public BranchDto setProjectUuid(String s) {
     this.projectUuid = s;
+    return this;
   }
 
   public boolean isMain() {
@@ -117,8 +119,9 @@ public class BranchDto {
     return keeType;
   }
 
-  public void setKeeType(BranchKeyType t) {
+  public BranchDto setKeeType(BranchKeyType t) {
     this.keeType = t;
+    return this;
   }
 
   /**
@@ -142,10 +145,11 @@ public class BranchDto {
     this.kee = s;
   }
 
-  public void setKey(@Nullable String s) {
+  public BranchDto setKey(@Nullable String s) {
     checkArgument(s == null || s.length() <= KEE_MAX_LENGTH, "Maximum length of branch name or pull request id is %s: %s", KEE_MAX_LENGTH, s);
     checkArgument(!NULL_KEY.equals(s), "Branch name is not allowed: %s", s);
     setKee(convertKeyToDb(s));
+    return this;
   }
 
   @Nullable
@@ -153,8 +157,9 @@ public class BranchDto {
     return branchType;
   }
 
-  public void setBranchType(@Nullable BranchType b) {
+  public BranchDto setBranchType(@Nullable BranchType b) {
     this.branchType = b;
+    return this;
   }
 
   @Nullable
@@ -162,8 +167,9 @@ public class BranchDto {
     return mergeBranchUuid;
   }
 
-  public void setMergeBranchUuid(@Nullable String s) {
+  public BranchDto setMergeBranchUuid(@Nullable String s) {
     this.mergeBranchUuid = s;
+    return this;
   }
 
   @Nullable
@@ -171,9 +177,10 @@ public class BranchDto {
     return pullRequestTitle;
   }
 
-  public void setPullRequestTitle(@Nullable String s) {
+  public BranchDto setPullRequestTitle(@Nullable String s) {
     checkArgument(s == null || s.length() <= 4000, "Maximum length of pull request title is 4000: %s", s);
     this.pullRequestTitle = s;
+    return this;
   }
 
   @Override
@@ -198,4 +205,5 @@ public class BranchDto {
   static String convertKeyFromDb(String s) {
     return NULL_KEY.equals(s) ? null : s;
   }
+
 }
index e5379b9ab91cd0250c2fcb767baed7eeec5d14d2..f12e59a954c1a1213933196792241da9092bda41 100644 (file)
@@ -214,6 +214,10 @@ public class ComponentDao implements Dao {
     return Optional.fromNullable(mapper(session).selectByKey(key));
   }
 
+  public java.util.Optional<ComponentDto> selectByKeyAndBranch(DbSession session, String key, String branch) {
+    return java.util.Optional.ofNullable(mapper(session).selectByDbKey(ComponentDto.generateBranchKey(key, branch)));
+  }
+
   public List<UuidWithProjectUuidDto> selectAllViewsAndSubViews(DbSession session) {
     return mapper(session).selectUuidsForQualifiers(Qualifiers.APP, Qualifiers.VIEW, Qualifiers.SUBVIEW);
   }
index 9e3b55062fa3fa58c1523da4e3c3430de7a16d87..9082e9710f0729a18df69957c676c60601d436af 100644 (file)
@@ -31,12 +31,20 @@ import org.apache.commons.lang.builder.ToStringBuilder;
 import org.sonar.api.resources.Scopes;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static java.lang.String.format;
 import static org.sonar.db.component.ComponentValidator.checkComponentKey;
 import static org.sonar.db.component.ComponentValidator.checkComponentName;
 import static org.sonar.db.component.DbTagsReader.readDbTags;
 
 public class ComponentDto {
 
+  /**
+   * Separator used to generate the key of the branch
+   */
+  public static final String BRANCH_KEY_SEPARATOR = ":BRANCH:";
+
+  private static final Splitter BRANCH_KEY_SPLITTER = Splitter.on(BRANCH_KEY_SEPARATOR);
+
   public static final String UUID_PATH_SEPARATOR = ".";
   public static final String UUID_PATH_OF_ROOT = UUID_PATH_SEPARATOR;
   private static final Splitter UUID_PATH_SPLITTER = Splitter.on(UUID_PATH_SEPARATOR).omitEmptyStrings();
@@ -108,7 +116,7 @@ public class ComponentDto {
 
   /**
    * On non-main branches only, {@link #uuid} of the main branch that represents
-   * the project ({@link #qualifier}="TRK").
+   * the project ({@link #qualifier}="TRK").x
    * It is propagated to all the components of the branch.
    *
    * Value is null on the main-branch components and on other kinds of components
@@ -216,6 +224,22 @@ public class ComponentDto {
     return this;
   }
 
+  /**
+   * The key to be displayed to user, doesn't contain information on branches
+   */
+  public String getKey() {
+    List<String> split = BRANCH_KEY_SPLITTER.splitToList(kee);
+    return split.size() == 2 ? split.get(0) : kee;
+  }
+
+  /**
+   * @return the key of the branch. It will be null on the main branch and when the component is not on a branch
+   */
+  @CheckForNull
+  public String getBranch(){
+    List<String> split = BRANCH_KEY_SPLITTER.splitToList(kee);
+    return split.size() == 2 ? split.get(1) : null;
+  }
 
   public String scope() {
     return scope;
@@ -503,4 +527,9 @@ public class ComponentDto {
     copy.createdAt = createdAt;
     return copy;
   }
+
+  // TODO Use it in branch plugin
+  public static String generateBranchKey(String componentKey, String branch) {
+    return format("%s%s%s", componentKey, BRANCH_KEY_SEPARATOR, branch);
+  }
 }
index 53ebb044c5a48852ed3bd9d35ba550a6abbd7c0d..692948c085cce45fcf1a3e4ed01d0e3f28079919 100644 (file)
@@ -33,6 +33,12 @@ public interface ComponentMapper {
   @CheckForNull
   ComponentDto selectByKey(String key);
 
+  /**
+   * This method should be used to get a component by its key without filtering out branches
+   */
+  @CheckForNull
+  ComponentDto selectByDbKey(String dbKey);
+
   @CheckForNull
   ComponentDto selectById(long id);
 
index 47b464dd2dd79910faf2af81348dd72c5fbc847a..0409bbd1f62d4962417b95050d31d371ad64a365 100644 (file)
       p.kee=#{key,jdbcType=VARCHAR}
   </select>
 
+  <select id="selectByDbKey" parameterType="String" resultType="Component">
+    SELECT
+    <include refid="componentColumns"/>
+    FROM projects p
+    where
+    p.kee=#{key,jdbcType=VARCHAR}
+  </select>
+
   <select id="selectComponentsHavingSameKeyOrderedById" parameterType="String" resultType="Component">
     select
     <include refid="componentColumns"/>
index 0f66805fdd43b9b8407fdde93348f70ee302a63a..e3f4e89f355328abadd1d407a5e41738e36a720d 100644 (file)
@@ -166,7 +166,8 @@ public class ComponentDaoTest {
     OrganizationDto organization = db.organizations().insert();
     ComponentDto project = db.components().insertPrivateProject(organization);
     ComponentDto directory = db.components().insertComponent(newDirectory(project, "src"));
-    ComponentDto file = db.components().insertComponent(newFileDto(directory)
+    ComponentDto file = db.components().insertComponent(newFileDto(project, directory)
+      .setDbKey("org.struts:struts-core:src/org/struts/RequestContext.java")
       .setName("RequestContext.java")
       .setLongName("org.struts.RequestContext")
       .setLanguage("java")
@@ -177,7 +178,7 @@ public class ComponentDaoTest {
     ComponentDto result = optional.get();
     assertThat(result.getOrganizationUuid()).isEqualTo(organization.getUuid());
     assertThat(result.uuid()).isEqualTo(file.uuid());
-    assertThat(result.getDbKey()).isEqualTo(file.getDbKey());
+    assertThat(result.getDbKey()).isEqualTo("org.struts:struts-core:src/org/struts/RequestContext.java");
     assertThat(result.path()).isEqualTo("src/RequestContext.java");
     assertThat(result.name()).isEqualTo("RequestContext.java");
     assertThat(result.longName()).isEqualTo("org.struts.RequestContext");
@@ -189,6 +190,18 @@ public class ComponentDaoTest {
     assertThat(underTest.selectByKey(dbSession, "unknown")).isAbsent();
   }
 
+  @Test
+  public void selectByKeyAndBranch() {
+    ComponentDto project = db.components().insertPrivateProject();
+    ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
+    ComponentDto file = db.components().insertComponent(newFileDto(branch));
+
+    assertThat(underTest.selectByKeyAndBranch(dbSession, project.getKey(), "my_branch").get().uuid()).isEqualTo(branch.uuid());
+    assertThat(underTest.selectByKeyAndBranch(dbSession, file.getKey(), "my_branch").get().uuid()).isEqualTo(file.uuid());
+    assertThat(underTest.selectByKeyAndBranch(dbSession, "unknown", "my_branch")).isNotPresent();
+    assertThat(underTest.selectByKeyAndBranch(dbSession, file.getKey(), "unknown")).isNotPresent();
+  }
+
   @Test
   public void selectOrFailByKey_fails_when_component_not_found() {
     db.components().insertPrivateProject();
index 916fac227552886ac96b3e3065db05d37f506a25..9723e0d689f7d91bd4f571892e0c9b0a82b482e4 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.db.component;
 import java.util.Arrays;
 import java.util.function.Consumer;
 import javax.annotation.Nullable;
+import org.sonar.core.util.Uuids;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
@@ -29,8 +30,12 @@ import org.sonar.db.organization.OrganizationDto;
 
 import static com.google.common.base.Preconditions.checkState;
 import static java.util.Arrays.asList;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+import static org.sonar.db.component.BranchKeyType.BRANCH;
+import static org.sonar.db.component.BranchType.LONG;
 import static org.sonar.db.component.ComponentTesting.newApplication;
 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
+import static org.sonar.db.component.ComponentTesting.newProjectBranch;
 import static org.sonar.db.component.ComponentTesting.newPublicProjectDto;
 import static org.sonar.db.component.ComponentTesting.newSubView;
 import static org.sonar.db.component.ComponentTesting.newView;
@@ -196,9 +201,19 @@ public class ComponentDbTester {
     db.commit();
   }
 
-  public ComponentDto insertProjectBranch(ComponentDto project, String branchName) {
-    ComponentDto branch = ComponentTesting.newProjectBranch(project, branchName);
+  @SafeVarargs
+  public final ComponentDto insertProjectBranch(ComponentDto project, Consumer<BranchDto>... dtoPopulators) {
+    String uuid = Uuids.createFast();
+    BranchDto branchDto = new BranchDto()
+      .setKey(randomAlphanumeric(255))
+      .setUuid(uuid)
+      .setProjectUuid(project.uuid())
+      .setKeeType(BRANCH)
+      .setBranchType(LONG);
+    Arrays.stream(dtoPopulators).forEach(dtoPopulator -> dtoPopulator.accept(branchDto));
+    ComponentDto branch = newProjectBranch(project, branchDto);
     insertComponent(branch);
+    dbClient.branchDao().insert(dbSession, branchDto);
     db.commit();
     return branch;
   }
index b4e997d24bcb6d8e826d1777ca07ced76a1dd53b..143f2abdf435f509d4229e584d829330d660fe07 100644 (file)
@@ -48,6 +48,7 @@ public class ComponentDtoTest {
     assertThat(componentDto.getId()).isEqualTo(1L);
     assertThat(componentDto.getDbKey()).isEqualTo("org.struts:struts-core:src/org/struts/RequestContext.java");
     assertThat(componentDto.deprecatedKey()).isEqualTo("org.struts:struts-core:src/org/struts/RequestContext.java");
+    assertThat(componentDto.getBranch()).isNull();
     assertThat(componentDto.name()).isEqualTo("RequestContext.java");
     assertThat(componentDto.longName()).isEqualTo("org.struts.RequestContext");
     assertThat(componentDto.qualifier()).isEqualTo("FIL");
@@ -103,4 +104,15 @@ public class ComponentDtoTest {
     ComponentDto nonRoot = new ComponentDto().setUuidPath(".12.34.56.");
     assertThat(nonRoot.getUuidPathAsList()).containsExactly("12", "34", "56");
   }
+
+  @Test
+  public void test_getKey_and_getBranch() {
+    ComponentDto underTest = new ComponentDto().setDbKey("my_key:BRANCH:my_branch");
+    assertThat(underTest.getKey()).isEqualTo("my_key");
+    assertThat(underTest.getBranch()).isEqualTo("my_branch");
+
+    underTest = new ComponentDto().setDbKey("my_key");
+    assertThat(underTest.getKey()).isEqualTo("my_key");
+    assertThat(underTest.getBranch()).isNull();
+  }
 }
index 08d0854f7b4aec57e25ce28ec73a30b8f6b58627..571b29cf47dc7473420359d4581c660644a7fdf3 100644 (file)
@@ -44,7 +44,7 @@ public class ComponentTesting {
     String filename = "NAME_" + fileUuid;
     String path = directory != null ? directory.path() + "/" + filename : module.path() + "/" + filename;
     return newChildComponent(fileUuid, module, directory == null ? module : directory)
-      .setDbKey("KEY_" + fileUuid)
+      .setDbKey(generateKey("FILE_KEY_" + fileUuid, module))
       .setName(filename)
       .setLongName(path)
       .setScope(Scopes.FILE)
@@ -59,8 +59,9 @@ public class ComponentTesting {
   }
 
   public static ComponentDto newDirectory(ComponentDto module, String uuid, String path) {
+    String key = !path.equals("/") ? module.getKey() + ":" + path : module.getKey() + ":/";
     return newChildComponent(uuid, module, module)
-      .setDbKey(!path.equals("/") ? module.getDbKey() + ":" + path : module.getDbKey() + ":/")
+      .setDbKey(generateKey(key, module))
       .setName(path)
       .setLongName(path)
       .setPath(path)
@@ -86,7 +87,7 @@ public class ComponentTesting {
   public static ComponentDto newModuleDto(String uuid, ComponentDto parentModuleOrProject) {
     return newChildComponent(uuid, parentModuleOrProject, parentModuleOrProject)
       .setModuleUuidPath(parentModuleOrProject.moduleUuidPath() + uuid + UUID_PATH_SEPARATOR)
-      .setDbKey("KEY_" + uuid)
+      .setDbKey(generateKey("MODULE_KEY_" + uuid, parentModuleOrProject))
       .setName("NAME_" + uuid)
       .setLongName("LONG_NAME_" + uuid)
       .setPath("module")
@@ -95,6 +96,11 @@ public class ComponentTesting {
       .setLanguage(null);
   }
 
+  private static String generateKey(String key, ComponentDto parentModuleOrProject) {
+    String branch = parentModuleOrProject.getBranch();
+    return branch == null ? key : ComponentDto.generateBranchKey(key, branch);
+  }
+
   public static ComponentDto newModuleDto(ComponentDto subProjectOrProject) {
     return newModuleDto(Uuids.createFast(), subProjectOrProject);
   }
@@ -194,10 +200,11 @@ public class ComponentTesting {
       .setPrivate(moduleOrProject.isPrivate());
   }
 
-  public static ComponentDto newProjectBranch(ComponentDto project, String branchName) {
+  public static ComponentDto newProjectBranch(ComponentDto project, BranchDto branchDto) {
     checkArgument(project.qualifier().equals(Qualifiers.PROJECT));
     checkArgument(project.getMainBranchProjectUuid() == null);
-    String uuid = Uuids.createFast();
+    String branchName = branchDto.getKey();
+    String uuid = branchDto.getUuid();
     return new ComponentDto()
       .setUuid(uuid)
       .setOrganizationUuid(project.getOrganizationUuid())
@@ -205,7 +212,8 @@ public class ComponentTesting {
       .setProjectUuid(uuid)
       .setModuleUuidPath(UUID_PATH_SEPARATOR + uuid + UUID_PATH_SEPARATOR)
       .setRootUuid(uuid)
-      .setDbKey(project.getDbKey() + ":BRANCH:" + branchName)
+      // name of the branch is not mandatory on the main branch
+      .setDbKey(branchName != null ? project.getDbKey() + ":BRANCH:" + branchName : project.getKey())
       .setMainBranchProjectUuid(project.uuid())
       .setName(project.name())
       .setLongName(project.longName())
index 321bbcbe8aa46f8ca2dd9ac6a061f358fd3551ad..5c475437ed3210c871244734aced9ec5db2f63c9 100644 (file)
@@ -264,8 +264,8 @@ public class ProjectMeasuresIndexerIteratorTest {
     SnapshotDto projectAnalysis = dbTester.components().insertProjectAndSnapshot(project);
     insertMeasure(project, projectAnalysis, metric, 10d);
 
-    ComponentDto branch = ComponentTesting.newProjectBranch(project, "feature/foo");
-    SnapshotDto branchAnalysis = dbTester.components().insertProjectAndSnapshot(branch);
+    ComponentDto branch = dbTester.components().insertProjectBranch(project, b -> b.setKey("feature/foo"));
+    SnapshotDto branchAnalysis = dbTester.components().insertSnapshot(branch);
     insertMeasure(branch, branchAnalysis, metric, 20d);
 
     Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById();
index bfd19284a952a9207c326cc044bf3585bf728489..c1bb50c861242df8afb1714a0fa3e7956aef8245 100644 (file)
@@ -39,15 +39,18 @@ import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.user.UserSession;
 import org.sonarqube.ws.MediaTypes;
 
+import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.collect.Maps.newHashMap;
 import static java.lang.String.format;
 import static org.sonar.api.web.UserRole.USER;
 import static org.sonar.core.util.Protobuf.setNullable;
+import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001;
 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
 
 public class IssuesAction implements BatchWsAction {
 
   private static final String PARAM_KEY = "key";
+  private static final String PARAM_BRANCH = "branch";
   private static final Splitter MODULE_PATH_SPLITTER = Splitter.on('.').trimResults().omitEmptyStrings();
 
   private final DbClient dbClient;
@@ -74,15 +77,19 @@ public class IssuesAction implements BatchWsAction {
       .setRequired(true)
       .setDescription("Project, module or file key")
       .setExampleValue(KEY_PROJECT_EXAMPLE_001);
+
+    action
+      .createParam(PARAM_BRANCH)
+      .setSince("6.6")
+      .setDescription("Branch key")
+      .setExampleValue(KEY_BRANCH_EXAMPLE_001);
   }
 
   @Override
   public void handle(Request request, Response response) throws Exception {
     try (DbSession dbSession = dbClient.openSession(false)) {
-      String componentKey = request.mandatoryParam(PARAM_KEY);
-      ComponentDto component = componentFinder.getByKey(dbSession, componentKey);
+      ComponentDto component = loadComponent(dbSession, request);
       userSession.checkComponentPermission(USER, component);
-
       Map<String, String> keysByUUid = keysByUUid(dbSession, component);
 
       ScannerInput.ServerIssue.Builder responseBuilder = ScannerInput.ServerIssue.newBuilder();
@@ -108,7 +115,7 @@ public class IssuesAction implements BatchWsAction {
   }
 
   private static void handleIssue(IssueDto issue, ScannerInput.ServerIssue.Builder issueBuilder,
-                                  Map<String, String> keysByUUid, OutputStream out) {
+    Map<String, String> keysByUUid, OutputStream out) {
     issueBuilder.setKey(issue.getKey());
     String moduleUuid = extractModuleUuid(issue);
     issueBuilder.setModuleKey(keysByUUid.get(moduleUuid));
@@ -135,7 +142,7 @@ public class IssuesAction implements BatchWsAction {
 
   private static String extractModuleUuid(IssueDto issue) {
     List<String> split = MODULE_PATH_SPLITTER.splitToList(issue.getModuleUuidPath());
-    return split.get(split.size()-1);
+    return split.get(split.size() - 1);
   }
 
   private Map<String, String> keysByUUid(DbSession session, ComponentDto component) {
@@ -143,16 +150,23 @@ public class IssuesAction implements BatchWsAction {
     if (Scopes.PROJECT.equals(component.scope())) {
       List<ComponentDto> modulesTree = dbClient.componentDao().selectDescendantModules(session, component.uuid());
       for (ComponentDto componentDto : modulesTree) {
-        keysByUUid.put(componentDto.uuid(), componentDto.getDbKey());
+        keysByUUid.put(componentDto.uuid(), componentDto.getKey());
       }
     } else {
       String moduleUuid = component.moduleUuid();
-      if (moduleUuid == null) {
-        throw new IllegalArgumentException(String.format("The component '%s' has no module uuid", component.uuid()));
-      }
+      checkArgument(moduleUuid != null, "The component '%s' has no module uuid", component.uuid());
       ComponentDto module = dbClient.componentDao().selectOrFailByUuid(session, moduleUuid);
-      keysByUUid.put(module.uuid(), module.getDbKey());
+      keysByUUid.put(module.uuid(), module.getKey());
     }
     return keysByUUid;
   }
+
+  private ComponentDto loadComponent(DbSession dbSession, Request request) {
+    String componentKey = request.mandatoryParam(PARAM_KEY);
+    String branch = request.param(PARAM_BRANCH);
+    if (branch != null) {
+      return componentFinder.getByKeyAndBranch(dbSession, componentKey, branch);
+    }
+    return componentFinder.getByKey(dbSession, componentKey);
+  }
 }
index 64200549f4ab4c949bb97d0d09a5a9c651383d1c..ec479bf2e2ee3900271bbfdacf5fb07b7893930d 100644 (file)
@@ -143,6 +143,10 @@ public class ComponentFinder {
     return checkFoundWithOptional(organizationDto, "Organization with uuid '%s' not found", organizationUuid);
   }
 
+  public ComponentDto getByKeyAndBranch(DbSession dbSession, String key, String branch) {
+    return checkFoundWithOptional(dbClient.componentDao().selectByKeyAndBranch(dbSession, key, branch), "Component '%s' on branch '%s' not found", key, branch);
+  }
+
   public enum ParamNames {
     PROJECT_ID_AND_KEY("projectId", "projectKey"),
     PROJECT_UUID_AND_KEY("projectUuid", "projectKey"),
index 93c1513a3e8c0d6050e3941cbdb375f2683a3e0a..fc4a971fee91879c5bffb58892e21733d2f9e0eb 100644 (file)
@@ -29,6 +29,8 @@ public class KeyExamples {
   public static final String KEY_ORG_EXAMPLE_001 = "my-org";
   public static final String KEY_ORG_EXAMPLE_002 = "foo-company";
 
+  public static final String KEY_BRANCH_EXAMPLE_001 = "feature/my_branch";
+
   private KeyExamples() {
     // prevent instantiation
   }
index d60c60980ac98f655806bd98b9ac6896edf5073f..582f7ea54ee571d79611efaaf51f7ab896a10c87 100644 (file)
@@ -20,6 +20,8 @@
 package org.sonar.server.batch;
 
 import java.io.IOException;
+import javax.annotation.Nullable;
+import org.assertj.core.groups.Tuple;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
@@ -37,9 +39,11 @@ import org.sonar.server.component.TestComponentFinder;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.TestResponse;
 import org.sonar.server.ws.WsActionTester;
 
+import static java.lang.String.format;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.tuple;
 import static org.sonar.api.rules.RuleType.BUG;
@@ -66,25 +70,24 @@ public class IssuesActionTest {
     ComponentDto project = db.components().insertPrivateProject();
     ComponentDto module = db.components().insertComponent(newModuleDto(project));
     ComponentDto file = db.components().insertComponent(newFileDto(module, null).setPath(null));
-    IssueDto issue = db.issues().insert(rule, project, file, i ->
-      i.setSeverity("BLOCKER")
-        // non-null fields
-        .setStatus("OPEN")
-        .setType(BUG)
-        .setManualSeverity(true)
-
-        // all the nullable fields
-        .setResolution(null)
-        .setMessage(null)
-        .setLine(null)
-        .setChecksum(null)
-        .setAssignee(null));
+    IssueDto issue = db.issues().insert(rule, project, file, i -> i.setSeverity("BLOCKER")
+      // non-null fields
+      .setStatus("OPEN")
+      .setType(BUG)
+      .setManualSeverity(true)
+
+      // all the nullable fields
+      .setResolution(null)
+      .setMessage(null)
+      .setLine(null)
+      .setChecksum(null)
+      .setAssignee(null));
     addPermissionTo(project);
 
-    ServerIssue serverIssue = call(project.getDbKey());
+    ServerIssue serverIssue = call(project.getKey());
 
     assertThat(serverIssue.getKey()).isEqualTo(issue.getKey());
-    assertThat(serverIssue.getModuleKey()).isEqualTo(module.getDbKey());
+    assertThat(serverIssue.getModuleKey()).isEqualTo(module.getKey());
     assertThat(serverIssue.getRuleRepository()).isEqualTo(rule.getRepositoryKey());
     assertThat(serverIssue.getRuleKey()).isEqualTo(rule.getRuleKey());
     assertThat(serverIssue.getStatus()).isEqualTo("OPEN");
@@ -106,22 +109,21 @@ public class IssuesActionTest {
     ComponentDto project = db.components().insertPrivateProject();
     ComponentDto module = db.components().insertComponent(newModuleDto(project));
     ComponentDto file = db.components().insertComponent(newFileDto(module, null));
-    IssueDto issue = db.issues().insert(rule, project, file, i ->
-      i.setSeverity("BLOCKER")
-        .setStatus("OPEN")
-        .setType(BUG)
-        .setManualSeverity(true)
-        .setResolution("FIXED")
-        .setMessage("the message")
-        .setLine(10)
-        .setChecksum("ABC")
-        .setAssignee("foo"));
+    IssueDto issue = db.issues().insert(rule, project, file, i -> i.setSeverity("BLOCKER")
+      .setStatus("OPEN")
+      .setType(BUG)
+      .setManualSeverity(true)
+      .setResolution("FIXED")
+      .setMessage("the message")
+      .setLine(10)
+      .setChecksum("ABC")
+      .setAssignee("foo"));
     addPermissionTo(project);
 
-    ServerIssue serverIssue = call(project.getDbKey());
+    ServerIssue serverIssue = call(project.getKey());
 
     assertThat(serverIssue.getKey()).isEqualTo(issue.getKey());
-    assertThat(serverIssue.getModuleKey()).isEqualTo(module.getDbKey());
+    assertThat(serverIssue.getModuleKey()).isEqualTo(module.getKey());
     assertThat(serverIssue.getRuleRepository()).isEqualTo(rule.getRepositoryKey());
     assertThat(serverIssue.getRuleKey()).isEqualTo(rule.getRuleKey());
     assertThat(serverIssue.getStatus()).isEqualTo("OPEN");
@@ -147,13 +149,13 @@ public class IssuesActionTest {
     IssueDto issueOnProject = db.issues().insert(rule, project, project, i -> i.setKee("ON_PROJECT"));
 
     addPermissionTo(project);
-    try (CloseableIterator<ServerIssue> result = callStream(project.getDbKey())) {
+    try (CloseableIterator<ServerIssue> result = callStream(project.getKey(), null)) {
       assertThat(result)
         .extracting(ServerIssue::getKey, ServerIssue::getModuleKey)
         .containsExactlyInAnyOrder(
-          tuple(issueOnFile.getKey(), module.getDbKey()),
-          tuple(issueOnModule.getKey(), module.getDbKey()),
-          tuple(issueOnProject.getKey(), project.getDbKey()));
+          tuple(issueOnFile.getKey(), module.getKey()),
+          tuple(issueOnModule.getKey(), module.getKey()),
+          tuple(issueOnProject.getKey(), project.getKey()));
     }
   }
 
@@ -168,12 +170,12 @@ public class IssuesActionTest {
     IssueDto issueOnProject = db.issues().insert(rule, project, project, i -> i.setKee("ON_PROJECT"));
 
     addPermissionTo(project);
-    try (CloseableIterator<ServerIssue> result = callStream(module.getDbKey())) {
+    try (CloseableIterator<ServerIssue> result = callStream(module.getKey(), null)) {
       assertThat(result)
         .extracting(ServerIssue::getKey, ServerIssue::getModuleKey)
         .containsExactlyInAnyOrder(
-          tuple(issueOnFile.getKey(), module.getDbKey()),
-          tuple(issueOnModule.getKey(), module.getDbKey()));
+          tuple(issueOnFile.getKey(), module.getKey()),
+          tuple(issueOnModule.getKey(), module.getKey()));
     }
   }
 
@@ -188,14 +190,49 @@ public class IssuesActionTest {
     IssueDto issueOnProject = db.issues().insert(rule, project, project);
 
     addPermissionTo(project);
-    try (CloseableIterator<ServerIssue> result = callStream(file.getDbKey())) {
+    try (CloseableIterator<ServerIssue> result = callStream(file.getKey(), null)) {
       assertThat(result)
         .extracting(ServerIssue::getKey, ServerIssue::getModuleKey)
         .containsExactlyInAnyOrder(
-          tuple(issueOnFile.getKey(), module.getDbKey()));
+          tuple(issueOnFile.getKey(), module.getKey()));
     }
   }
 
+  @Test
+  public void return_issues_by_project_and_branch() {
+    RuleDefinitionDto rule = db.rules().insert();
+    ComponentDto project = db.components().insertPrivateProject();
+    addPermissionTo(project);
+    ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
+    ComponentDto file = db.components().insertComponent(newFileDto(branch));
+    IssueDto issueOnFile = db.issues().insert(rule, branch, file);
+    IssueDto issueOnBranch = db.issues().insert(rule, branch, branch);
+
+    assertResult(project.getKey(), "my_branch",
+      tuple(issueOnFile.getKey(), branch.getKey()),
+      tuple(issueOnBranch.getKey(), branch.getKey()));
+  }
+
+  @Test
+  public void return_issues_by_module_and_branch() {
+    RuleDefinitionDto rule = db.rules().insert();
+    ComponentDto project = db.components().insertPrivateProject();
+    addPermissionTo(project);
+    ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
+    ComponentDto module = db.components().insertComponent(newModuleDto(branch));
+    ComponentDto subModule = db.components().insertComponent(newModuleDto(module));
+    ComponentDto file = db.components().insertComponent(newFileDto(subModule));
+    IssueDto issueOnFile = db.issues().insert(rule, branch, file);
+    IssueDto issueOnSubModule = db.issues().insert(rule, branch, subModule);
+    IssueDto issueOnModule = db.issues().insert(rule, branch, module);
+
+    assertResult(module.getKey(), "my_branch",
+      tuple(issueOnFile.getKey(), subModule.getKey()),
+      tuple(issueOnSubModule.getKey(), subModule.getKey()),
+      tuple(issueOnModule.getKey(), module.getKey())
+    );
+  }
+
   @Test
   public void fail_if_requested_component_is_a_directory() throws IOException {
     ComponentDto project = db.components().insertPrivateProject();
@@ -205,7 +242,7 @@ public class IssuesActionTest {
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("Component of scope 'DIR' is not allowed");
 
-    call(directory.getDbKey());
+    call(directory.getKey());
   }
 
   @Test
@@ -217,11 +254,11 @@ public class IssuesActionTest {
     IssueDto issue = db.issues().insert(rule, project, file);
 
     addPermissionTo(project);
-    try (CloseableIterator<ServerIssue> result = callStream(project.getDbKey())) {
+    try (CloseableIterator<ServerIssue> result = callStream(project.getKey(), null)) {
       // Module key of removed file should be returned
       assertThat(result)
         .extracting(ServerIssue::getKey, ServerIssue::getModuleKey)
-        .containsExactly(tuple(issue.getKey(), module.getDbKey()));
+        .containsExactly(tuple(issue.getKey(), module.getKey()));
     }
   }
 
@@ -232,7 +269,7 @@ public class IssuesActionTest {
 
     expectedException.expect(ForbiddenException.class);
 
-    tester.newRequest().setParam("key", file.getDbKey()).execute();
+    tester.newRequest().setParam("key", file.getKey()).execute();
   }
 
   @Test
@@ -243,6 +280,21 @@ public class IssuesActionTest {
     tester.newRequest().setParam("key", "does_not_exist").execute();
   }
 
+  @Test
+  public void fail_if_branch_does_not_exist() {
+    ComponentDto project = db.components().insertPrivateProject();
+     db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
+    addPermissionTo(project);
+
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage(format("Component '%s' on branch 'does_not_exist' not found", project.getKey()));
+
+    tester.newRequest()
+      .setParam("key",project.getKey())
+      .setParam("branch", "does_not_exist")
+      .execute();
+  }
+
   private void addPermissionTo(ComponentDto project) {
     userSessionRule.addProjectPermission(UserRole.USER, project);
   }
@@ -252,8 +304,20 @@ public class IssuesActionTest {
     return ServerIssue.parseDelimitedFrom(response.getInputStream());
   }
 
-  private CloseableIterator<ServerIssue> callStream(String componentKey) {
-    TestResponse response = tester.newRequest().setParam("key", componentKey).execute();
-    return Protobuf.readStream(response.getInputStream(), ServerIssue.parser());
+  private CloseableIterator<ServerIssue> callStream(String componentKey, @Nullable String branch) {
+    TestRequest request = tester.newRequest()
+      .setParam("key", componentKey);
+    if (branch != null) {
+      request.setParam("branch", branch);
+    }
+    return Protobuf.readStream(request.execute().getInputStream(), ServerIssue.parser());
+  }
+
+  private void assertResult(String componentKey, String branch, Tuple... tuples) {
+    try (CloseableIterator<ServerIssue> result = callStream(componentKey, branch)) {
+      assertThat(result)
+        .extracting(ServerIssue::getKey, ServerIssue::getModuleKey)
+        .containsExactlyInAnyOrder(tuples);
+    }
   }
 }
index fcccc22fb603219b7fac8d408bd2eb179efbdd40..c6dcd86eeaa6fafa4ea91403f2ad7af3d8168816 100644 (file)
@@ -28,8 +28,11 @@ import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.server.exceptions.NotFoundException;
 
+import static java.lang.String.format;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.db.component.ComponentTesting.newDirectory;
 import static org.sonar.db.component.ComponentTesting.newFileDto;
+import static org.sonar.db.component.ComponentTesting.newModuleDto;
 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
 import static org.sonar.server.component.ComponentFinder.ParamNames.ID_AND_KEY;
 
@@ -108,7 +111,6 @@ public class ComponentFinderTest {
     ComponentDto project = db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization()));
     db.components().insertComponent(newFileDto(project).setDbKey("file-key").setEnabled(false));
 
-
     expectedException.expect(NotFoundException.class);
     expectedException.expectMessage("Component key 'file-key' not found");
 
@@ -132,4 +134,30 @@ public class ComponentFinderTest {
 
     assertThat(component.getDbKey()).isEqualTo("project-key");
   }
+
+  @Test
+  public void get_by_key_and_branch() {
+    ComponentDto project = db.components().insertPrivateProject();
+    ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
+    ComponentDto module = db.components().insertComponent(newModuleDto(branch));
+    ComponentDto directory = db.components().insertComponent(newDirectory(module, "scr"));
+    ComponentDto file = db.components().insertComponent(newFileDto(module));
+
+    assertThat(underTest.getByKeyAndBranch(dbSession, project.getKey(), "my_branch").uuid()).isEqualTo(branch.uuid());
+    assertThat(underTest.getByKeyAndBranch(dbSession, module.getKey(), "my_branch").uuid()).isEqualTo(module.uuid());
+    assertThat(underTest.getByKeyAndBranch(dbSession, file.getKey(), "my_branch").uuid()).isEqualTo(file.uuid());
+    assertThat(underTest.getByKeyAndBranch(dbSession, directory.getKey(), "my_branch").uuid()).isEqualTo(directory.uuid());
+  }
+
+  @Test
+  public void fail_to_get_by_key_and_branch_when_branch_does_not_exist() {
+    ComponentDto project = db.components().insertPrivateProject();
+    ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
+    ComponentDto file = db.components().insertComponent(newFileDto(branch));
+
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage(format("Component '%s' on branch 'other_branch' not found", file.getKey()));
+
+    underTest.getByKeyAndBranch(dbSession, file.getKey(), "other_branch");
+  }
 }
index 475499144067129ec0afbb5acc23afb7dfad3069..74de66dae6b892253802e7981ff8d8e7704fe21c 100644 (file)
@@ -86,7 +86,7 @@ public class ComponentIndexerTest {
   @Test
   public void indexOnStartup_does_not_index_non_main_branches() {
     ComponentDto project = db.components().insertPrivateProject();
-    ComponentDto branch = db.components().insertProjectBranch(project, "feature/foo");
+    ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("feature/foo"));
 
     underTest.indexOnStartup(emptySet());
 
@@ -133,7 +133,7 @@ public class ComponentIndexerTest {
   @Test
   public void indexOnAnalysis_does_not_index_non_main_branches() {
     ComponentDto project = db.components().insertPrivateProject();
-    ComponentDto branch = db.components().insertProjectBranch(project, "feature/foo");
+    ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("feature/foo"));
 
     underTest.indexOnAnalysis(branch.uuid());
 
index dd42cc7e85e32092c45cd6597b2df224672a3cf3..5d9e3245848caf4ddf54b0f2b71ad28e6ba6f848 100644 (file)
@@ -193,7 +193,6 @@ public class IssueIndexerTest {
     assertThatEsQueueTableHasSize(0);
   }
 
-
   @Test
   public void index_is_not_updated_when_creating_project() {
     // it's impossible to already have an issue on a project
@@ -452,7 +451,7 @@ public class IssueIndexerTest {
   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 branch = db.components().insertProjectBranch(project, b -> b.setKey("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));
index e8f63c4a87c762757b04a97fcb8a732f6f9ded83..7f5d6ca4a9bfab1449f0b74ee3311cc05865acd7 100644 (file)
@@ -96,7 +96,7 @@ public class ProjectMeasuresIndexerTest {
   @Test
   public void indexOnStartup_ignores_non_main_branches() {
     ComponentDto project = db.components().insertPrivateProject();
-    ComponentDto branch = db.components().insertProjectBranch(project, "feature/foo");
+    ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("feature/foo"));
 
     underTest.indexOnStartup(emptySet());
 
@@ -202,7 +202,7 @@ public class ProjectMeasuresIndexerTest {
   @Test
   public void non_main_branches_are_not_indexed_during_analysis() {
     ComponentDto project = db.components().insertPrivateProject();
-    ComponentDto branch = db.components().insertProjectBranch(project, "feature/foo");
+    ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("feature/foo"));
 
     underTest.indexOnAnalysis(branch.uuid());
 
index 53f7a58cf606fe911065296a0714bcab3d195e9d..cf0207382d86096ec802af2f0056eb9fcb7c379a 100644 (file)
@@ -27,9 +27,6 @@ import org.sonar.api.utils.System2;
 import org.sonar.api.web.UserRole;
 import org.sonar.db.DbTester;
 import org.sonar.db.RowNotFoundException;
-import org.sonar.db.component.BranchDto;
-import org.sonar.db.component.BranchKeyType;
-import org.sonar.db.component.BranchType;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ComponentTesting;
 import org.sonar.server.tester.UserSessionRule;
@@ -111,8 +108,8 @@ public class ListActionTest {
   @Test
   public void test_project_with_branches() {
     ComponentDto project = db.components().insertPrivateProject();
-    insertBranch(project, "feature/bar");
-    insertBranch(project, "feature/foo");
+    db.components().insertProjectBranch(project, b -> b.setKey("feature/bar"));
+    db.components().insertProjectBranch(project, b -> b.setKey("feature/foo"));
     userSession.logIn().addProjectPermission(UserRole.USER, project);
 
     ListWsResponse response = tester.newRequest()
@@ -128,8 +125,8 @@ public class ListActionTest {
   @Test
   public void test_example() {
     ComponentDto project = db.components().insertPrivateProject();
-    insertBranch(project, "feature/bar");
-    insertBranch(project, "feature/foo");
+    db.components().insertProjectBranch(project, b -> b.setKey("feature/bar"));
+    db.components().insertProjectBranch(project, b -> b.setKey("feature/foo"));
     userSession.logIn().addProjectPermission(UserRole.USER, project);
 
     String json = tester.newRequest()
@@ -140,15 +137,4 @@ public class ListActionTest {
     assertJson(json).isSimilarTo(tester.getDef().responseExampleAsString());
   }
 
-  private void insertBranch(ComponentDto project, String branchName) {
-    ComponentDto branch = db.components().insertProjectBranch(project, branchName);
-    BranchDto branchDto = new BranchDto();
-    branchDto.setUuid(branch.uuid());
-    branchDto.setProjectUuid(project.uuid());
-    branchDto.setBranchType(BranchType.LONG);
-    branchDto.setKeeType(BranchKeyType.BRANCH);
-    branchDto.setKey(branchName);
-    db.getDbClient().branchDao().insert(db.getSession(), branchDto);
-    db.commit();
-  }
 }
index 83b0fb4cdf76aa737ea042a91b4086a1bf910cc0..b4fff65d1c7e5b90f69d2419e53a20ae7a066f36 100644 (file)
@@ -518,7 +518,7 @@ public class ServerUserSessionTest {
 
   @Test
   public void hasComponentPermission_on_branch_checks_permissions_of_its_project() {
-    ComponentDto branch = db.components().insertProjectBranch(privateProject, "feature/foo");
+    ComponentDto branch = db.components().insertProjectBranch(privateProject, b -> b.setKey("feature/foo"));
     ComponentDto fileInBranch = db.components().insertComponent(newChildComponent("fileUuid", branch, branch));
 
     // permissions are defined on the project, not on the branch