]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-14566 Update SonarQube main branch name during Github project onboarding
authorBelen Pruvost <belen.pruvost@sonarsource.com>
Wed, 10 Mar 2021 07:37:10 +0000 (08:37 +0100)
committersonartech <sonartech@sonarsource.com>
Tue, 16 Mar 2021 20:08:15 +0000 (20:08 +0000)
server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClient.java
server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClientImpl.java
server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubBinding.java
server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GithubApplicationClientImplTest.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/ImportHelper.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/ImportHelperTest.java [new file with mode: 0644]
server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/github/ListGithubRepositoriesActionTest.java

index 13260a3e18c20b585e8c0abd0ccc407b11b00524..cb97116d9c0a19ffc0b50f6bc95af62c03f18e19 100644 (file)
@@ -102,13 +102,15 @@ public interface GithubApplicationClient {
     private final boolean isPrivate;
     private final String fullName;
     private final String url;
+    private final String defaultBranch;
 
-    public Repository(long id, String name, boolean isPrivate, String fullName, String url) {
+    public Repository(long id, String name, boolean isPrivate, String fullName, String url, String defaultBranch) {
       this.id = id;
       this.name = name;
       this.isPrivate = isPrivate;
       this.fullName = fullName;
       this.url = url;
+      this.defaultBranch = defaultBranch;
     }
 
     public long getId() {
@@ -131,6 +133,10 @@ public interface GithubApplicationClient {
       return url;
     }
 
+    public String getDefaultBranch() {
+      return defaultBranch;
+    }
+
     @Override
     public String toString() {
       return "Repository{" +
index 3fc473526739a7c373f1acd9fef42f80e7b5d428..ddb72bd65f18b0af2839c2f81df3e893f29653a0 100644 (file)
@@ -183,7 +183,7 @@ public class GithubApplicationClientImpl implements GithubApplicationClient {
 
       if (gsonRepositories.get().items != null) {
         repositories.setRepositories(gsonRepositories.get().items.stream()
-          .map(gsonRepository -> new Repository(gsonRepository.id, gsonRepository.name, gsonRepository.isPrivate, gsonRepository.fullName, gsonRepository.url))
+          .map(GsonGithubRepository::toRepository)
           .collect(toList()));
       }
 
@@ -200,7 +200,7 @@ public class GithubApplicationClientImpl implements GithubApplicationClient {
       GetResponse response = appHttpClient.get(appUrl, accessToken, String.format("/repos/%s", repositoryKey));
       return response.getContent()
         .map(content -> GSON.fromJson(content, GsonGithubRepository.class))
-        .map(repository -> new Repository(repository.id, repository.name, repository.isPrivate, repository.fullName, repository.url));
+        .map(GsonGithubRepository::toRepository);
     } catch (Exception e) {
       throw new IllegalStateException(format("Failed to get repository '%s' of '%s' accessible by user access token on '%s'", repositoryKey, organization, appUrl), e);
     }
index 83a6a08e77a9bb501134129d9bb9caf15ff5b055..ce6e207bf707afb1c2799555033eafbf1a06b2b7 100644 (file)
@@ -22,6 +22,8 @@ package org.sonar.alm.client.github;
 import com.google.gson.annotations.SerializedName;
 import java.util.List;
 
+import static org.sonar.alm.client.github.GithubApplicationClient.*;
+
 public class GithubBinding {
 
   private GithubBinding() {
@@ -138,11 +140,18 @@ public class GithubBinding {
     boolean isPrivate;
     @SerializedName("url")
     String url;
+    @SerializedName("default_branch")
+    String defaultBranch;
 
     public GsonGithubRepository() {
       // even if empty constructor is not required for Gson, it is strongly
       // recommended:
       // http://stackoverflow.com/a/18645370/229031
     }
+
+    public Repository toRepository() {
+      return new Repository(this.id, this.name, this.isPrivate, this.fullName,
+        this.url, this.defaultBranch);
+    }
   }
 }
index 4cf51c3f5dfec15848307b75690596f7626ebeec..f98a7ce8620605d64821a4ab6913799b15c8f18f 100644 (file)
@@ -793,8 +793,8 @@ public class GithubApplicationClientImplTest {
       .isPresent()
       .get()
       .extracting(GithubApplicationClient.Repository::getId, GithubApplicationClient.Repository::getName, GithubApplicationClient.Repository::getFullName,
-        GithubApplicationClient.Repository::getUrl, GithubApplicationClient.Repository::isPrivate)
-      .containsOnly(1296269L, "Hello-World", "octocat/Hello-World", "https://github.sonarsource.com/api/v3/repos/octocat/Hello-World", false);
+        GithubApplicationClient.Repository::getUrl, GithubApplicationClient.Repository::isPrivate, GithubApplicationClient.Repository::getDefaultBranch)
+      .containsOnly(1296269L, "Hello-World", "octocat/Hello-World", "https://github.sonarsource.com/api/v3/repos/octocat/Hello-World", false, "master");
   }
 
   private AppToken mockAppToken() {
index 7f6fb0c1bbbe5070f6549bfc556701906dbc0cb1..14d572d7fbbab1efa0b3842664eed01021547470 100644 (file)
@@ -72,5 +72,4 @@ public class ImportHelper {
         .setVisibility(Visibility.getLabel(componentDto.isPrivate())))
       .build();
   }
-
 }
index eb1f31a61808e21c83d5cf3b5fd9156ee18f351c..3b093435d65f4689f4efcf8459b3ef94e03dcf4a 100644 (file)
@@ -61,7 +61,7 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction {
   private final ImportHelper importHelper;
 
   public ImportGithubProjectAction(DbClient dbClient, UserSession userSession, ProjectDefaultVisibility projectDefaultVisibility,
-      GithubApplicationClientImpl githubApplicationClient, ComponentUpdater componentUpdater, ImportHelper importHelper) {
+    GithubApplicationClientImpl githubApplicationClient, ComponentUpdater componentUpdater, ImportHelper importHelper) {
     this.dbClient = dbClient;
     this.userSession = userSession;
     this.projectDefaultVisibility = projectDefaultVisibility;
@@ -121,22 +121,23 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction {
       Repository repository = githubApplicationClient.getRepository(url, accessToken, githubOrganization, repositoryKey)
         .orElseThrow(() -> new NotFoundException(String.format("GitHub repository '%s' not found", repositoryKey)));
 
-      ComponentDto componentDto = createProject(dbSession, repository);
+      ComponentDto componentDto = createProject(dbSession, repository, repository.getDefaultBranch());
       populatePRSetting(dbSession, repository, componentDto, almSettingDto);
+      componentUpdater.commitAndIndex(dbSession, componentDto);
 
       return toCreateResponse(componentDto);
     }
   }
 
-  private ComponentDto createProject(DbSession dbSession, Repository repo) {
+  private ComponentDto createProject(DbSession dbSession, Repository repo, String mainBranchName) {
     boolean visibility = projectDefaultVisibility.get(dbSession).isPrivate();
-    return componentUpdater.create(dbSession, newComponentBuilder()
+    return componentUpdater.createWithoutCommit(dbSession, newComponentBuilder()
       .setKey(getProjectKeyFromRepository(repo))
       .setName(repo.getName())
       .setPrivate(visibility)
       .setQualifier(PROJECT)
       .build(),
-      userSession.getUuid());
+      userSession.getUuid(), mainBranchName, s -> {});
   }
 
   static String getProjectKeyFromRepository(Repository repo) {
@@ -152,6 +153,5 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction {
       .setSummaryCommentEnabled(true)
       .setMonorepo(false);
     dbClient.projectAlmSettingDao().insertOrUpdate(dbSession, projectAlmSettingDto);
-    dbSession.commit();
   }
 }
index 358631712893d5819cde92085ba22663bf2a0714..5a1c8a23c04e4ba968041bf141cf442b2db8bb78 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.server.component;
 import com.google.common.collect.ImmutableSet;
 import java.util.Date;
 import java.util.Locale;
+import java.util.Optional;
 import java.util.Set;
 import java.util.function.Consumer;
 import javax.annotation.Nullable;
@@ -88,11 +89,22 @@ public class ComponentUpdater {
    * Create component without committing.
    * Don't forget to call commitAndIndex(...) when ready to commit.
    */
-  public ComponentDto createWithoutCommit(DbSession dbSession, NewComponent newComponent, @Nullable String userUuid, Consumer<ComponentDto> componentModifier) {
+  public ComponentDto createWithoutCommit(DbSession dbSession, NewComponent newComponent,
+    @Nullable String userUuid, Consumer<ComponentDto> componentModifier) {
+    return createWithoutCommit(dbSession, newComponent, userUuid, null, componentModifier);
+  }
+
+  /**
+   * Create component without committing.
+   * Don't forget to call commitAndIndex(...) when ready to commit.
+   */
+  public ComponentDto createWithoutCommit(DbSession dbSession, NewComponent newComponent,
+    @Nullable String userUuid, @Nullable String mainBranchName,
+    Consumer<ComponentDto> componentModifier) {
     checkKeyFormat(newComponent.qualifier(), newComponent.key());
     ComponentDto componentDto = createRootComponent(dbSession, newComponent, componentModifier);
     if (isRootProject(componentDto)) {
-      createMainBranch(dbSession, componentDto.uuid());
+      createMainBranch(dbSession, componentDto.uuid(), mainBranchName);
     }
     handlePermissionTemplate(dbSession, componentDto, userUuid);
     return componentDto;
@@ -152,11 +164,11 @@ public class ComponentUpdater {
       && MAIN_BRANCH_QUALIFIERS.contains(componentDto.qualifier());
   }
 
-  private void createMainBranch(DbSession session, String componentUuid) {
+  private void createMainBranch(DbSession session, String componentUuid, @Nullable String mainBranch) {
     BranchDto branch = new BranchDto()
       .setBranchType(BranchType.BRANCH)
       .setUuid(componentUuid)
-      .setKey(BranchDto.DEFAULT_MAIN_BRANCH_NAME)
+      .setKey(Optional.ofNullable(mainBranch).orElse(BranchDto.DEFAULT_MAIN_BRANCH_NAME))
       .setMergeBranchUuid(null)
       .setExcludeFromPurge(true)
       .setProjectUuid(componentUuid);
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/ImportHelperTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/ImportHelperTest.java
new file mode 100644 (file)
index 0000000..b6e64c1
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.
+ */
+package org.sonar.server.almintegration.ws;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.BranchDto;
+import org.sonar.db.component.BranchType;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ComponentTesting;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.tester.UserSessionRule;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonarqube.ws.Projects.CreateWsResponse;
+
+public class ImportHelperTest {
+
+  private final System2 system2 = System2.INSTANCE;
+  private final ComponentDto componentDto = ComponentTesting.newPublicProjectDto();
+  private final BranchDto branchDto = new BranchDto()
+    .setBranchType(BranchType.BRANCH)
+    .setKey("main")
+    .setUuid(componentDto.uuid())
+    .setProjectUuid(componentDto.uuid());
+  private final Request request = mock(Request.class);
+
+  @Rule
+  public final DbTester db = DbTester.create(system2);
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  private ImportHelper underTest = new ImportHelper(db.getDbClient(), userSession);
+
+  @Test
+  public void it_throws_exception_when_provisioning_project_without_permission() {
+    assertThatThrownBy(() -> underTest.checkProvisionProjectPermission())
+      .isInstanceOf(UnauthorizedException.class)
+      .hasMessage("Authentication is required");
+  }
+
+  @Test
+  public void it_throws_exception_on_get_alm_setting_when_key_is_empty() {
+    assertThatThrownBy(() -> underTest.getAlmSetting(request))
+      .isInstanceOf(NotFoundException.class);
+  }
+
+  @Test
+  public void it_throws_exception_on_get_alm_setting_when_key_is_not_found() {
+    when(request.mandatoryParam("almSetting")).thenReturn("key");
+    assertThatThrownBy(() -> underTest.getAlmSetting(request))
+      .isInstanceOf(NotFoundException.class)
+      .hasMessage("ALM Setting 'key' not found");
+  }
+
+  @Test
+  public void it_throws_exception_when_user_uuid_is_null() {
+    assertThatThrownBy(() -> underTest.getUserUuid())
+      .isInstanceOf(NullPointerException.class)
+      .hasMessage("User UUID cannot be null");
+  }
+
+  @Test
+  public void it_returns_create_response() {
+    CreateWsResponse response = ImportHelper.toCreateResponse(componentDto);
+    CreateWsResponse.Project project = response.getProject();
+
+    assertThat(project).extracting(CreateWsResponse.Project::getKey, CreateWsResponse.Project::getName,
+      CreateWsResponse.Project::getQualifier)
+      .containsExactly(componentDto.getDbKey(), componentDto.name(), componentDto.qualifier());
+  }
+}
index 563e40b955a06a58f02f3e5b5e84dbeba95c62f6..02be206424c49c0ceed3cb43f0f57115ce4c5f5b 100644 (file)
@@ -31,6 +31,7 @@ import org.sonar.core.i18n.I18n;
 import org.sonar.core.util.SequenceUuidFactory;
 import org.sonar.db.DbTester;
 import org.sonar.db.alm.setting.AlmSettingDto;
+import org.sonar.db.component.BranchDto;
 import org.sonar.db.permission.GlobalPermission;
 import org.sonar.db.project.ProjectDto;
 import org.sonar.db.user.UserDto;
@@ -90,7 +91,7 @@ public class ImportGithubProjectActionTest {
     db.almPats().insert(p -> p.setAlmSettingUuid(githubAlmSetting.getUuid()).setUserUuid(userSession.getUuid()));
 
     GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, "Hello-World", false, "octocat/Hello-World",
-      "https://github.sonarsource.com/api/v3/repos/octocat/Hello-World");
+      "https://github.sonarsource.com/api/v3/repos/octocat/Hello-World", "default-branch");
     when(appClient.getRepository(any(), any(), any(), any()))
       .thenReturn(Optional.of(repository));
 
@@ -107,6 +108,9 @@ public class ImportGithubProjectActionTest {
     Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
     assertThat(projectDto).isPresent();
     assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), projectDto.get())).isPresent();
+    Optional<BranchDto> mainBranch = db.getDbClient().branchDao().selectByProject(db.getSession(), projectDto.get()).stream().filter(BranchDto::isMain).findAny();
+    assertThat(mainBranch).isPresent();
+    assertThat(mainBranch.get().getKey()).isEqualTo("default-branch");
   }
 
   @Test
@@ -116,7 +120,7 @@ public class ImportGithubProjectActionTest {
     db.components().insertPublicProject(p -> p.setDbKey("octocat_Hello-World"));
 
     GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, "Hello-World", false, "octocat/Hello-World",
-      "https://github.sonarsource.com/api/v3/repos/octocat/Hello-World");
+      "https://github.sonarsource.com/api/v3/repos/octocat/Hello-World", "main");
     when(appClient.getRepository(any(), any(), any(), any()))
       .thenReturn(Optional.of(repository));
 
index 42bba3926ce4ad0e713e6f3cb3baf38e96cbf17a..66fd47a2ad2208e8dbbb5a159d6f3df427977e28 100644 (file)
@@ -107,7 +107,8 @@ public class ListGithubRepositoriesActionTest {
         .thenReturn(new GithubApplicationClient.Repositories()
           .setTotal(2)
           .setRepositories(Stream.of("HelloWorld", "HelloUniverse")
-            .map(name -> new GithubApplicationClient.Repository(name.length(), name, false, "github/" + name, "https://github-enterprise.sonarqube.com/api/v3/github/HelloWorld"))
+            .map(name -> new GithubApplicationClient.Repository(name.length(), name, false, "github/" + name,
+              "https://github-enterprise.sonarqube.com/api/v3/github/HelloWorld", "main"))
             .collect(Collectors.toList())));
 
     ProjectDto project = db.components().insertPrivateProjectDto(componentDto -> componentDto.setDbKey("github_HelloWorld"));