From fd513c22716ed0ba53fe34dadbd74334d96621fd Mon Sep 17 00:00:00 2001 From: Philippe Perrin Date: Wed, 10 Mar 2021 09:33:56 +0100 Subject: [PATCH] SONAR-14564 Update SonarQube main branch name during Azure DevOps project onboarding --- .../sonar/alm/client/azure/GsonAzureRepo.java | 20 ++++++- .../azure/AzureDevOpsHttpClientTest.java | 2 + .../alm/client/azure/GsonAzureRepoTest.java | 58 +++++++++++++++++++ .../ws/azure/ImportAzureProjectAction.java | 19 +++--- .../azure/ImportAzureProjectActionTest.java | 52 ++++++++++++++++- .../ws/azure/SearchAzureReposActionTest.java | 2 +- 6 files changed, 142 insertions(+), 11 deletions(-) create mode 100644 server/sonar-alm-client/src/test/java/org/sonar/alm/client/azure/GsonAzureRepoTest.java diff --git a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/azure/GsonAzureRepo.java b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/azure/GsonAzureRepo.java index 60327fc5c63..b8439809817 100644 --- a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/azure/GsonAzureRepo.java +++ b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/azure/GsonAzureRepo.java @@ -20,8 +20,11 @@ package org.sonar.alm.client.azure; import com.google.gson.annotations.SerializedName; +import java.util.regex.Pattern; public class GsonAzureRepo { + private static final String BRANCH_FULL_NAME_PREFIX = "refs/heads/"; + @SerializedName("id") private String id; @@ -34,15 +37,19 @@ public class GsonAzureRepo { @SerializedName("project") private GsonAzureProject project; + @SerializedName("defaultBranch") + private String defaultBranchFullName; + public GsonAzureRepo() { // http://stackoverflow.com/a/18645370/229031 } - public GsonAzureRepo(String id, String name, String url, GsonAzureProject project) { + public GsonAzureRepo(String id, String name, String url, GsonAzureProject project, String defaultBranchFullName) { this.id = id; this.name = name; this.url = url; this.project = project; + this.defaultBranchFullName = defaultBranchFullName; } public String getId() { @@ -60,4 +67,15 @@ public class GsonAzureRepo { public GsonAzureProject getProject() { return project; } + + public String getDefaultBranchName() { + if (defaultBranchFullName == null || defaultBranchFullName.equals("")) { + return null; + } + + return Pattern + .compile(Pattern.quote(BRANCH_FULL_NAME_PREFIX), Pattern.CASE_INSENSITIVE) + .matcher(defaultBranchFullName) + .replaceAll(""); + } } diff --git a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/azure/AzureDevOpsHttpClientTest.java b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/azure/AzureDevOpsHttpClientTest.java index 40d3407943f..da1ea680661 100644 --- a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/azure/AzureDevOpsHttpClientTest.java +++ b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/azure/AzureDevOpsHttpClientTest.java @@ -243,6 +243,7 @@ public class AzureDevOpsHttpClientTest { " \"name\": \"Project-Name\",\n" + " \"description\": \"Project's description\" \n" + " },\n" + + " \"defaultBranch\": \"refs/heads/default-branch\",\n" + " \"size\": 0" + "}"); @@ -260,6 +261,7 @@ public class AzureDevOpsHttpClientTest { assertThat(repo.getName()).isEqualTo("Repo-Name-1"); assertThat(repo.getUrl()).isEqualTo("https://ado.sonarqube.com/DefaultCollection/Repo-Id-1"); assertThat(repo.getProject().getName()).isEqualTo("Project-Name"); + assertThat(repo.getDefaultBranchName()).isEqualTo("default-branch"); } @Test diff --git a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/azure/GsonAzureRepoTest.java b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/azure/GsonAzureRepoTest.java new file mode 100644 index 00000000000..f5f12aa0677 --- /dev/null +++ b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/azure/GsonAzureRepoTest.java @@ -0,0 +1,58 @@ +/* + * 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.alm.client.azure; + +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(DataProviderRunner.class) +public class GsonAzureRepoTest { + @Test + @UseDataProvider("data") + public void extract_branch_name_from_full_branch_name(String actualFullBranchName, String expectedBranchName) { + GsonAzureRepo repo = new GsonAzureRepo( + "repo_id", + "repo_name", + "repo_url", + new GsonAzureProject(), + actualFullBranchName + ); + + assertThat(repo.getDefaultBranchName()).isEqualTo(expectedBranchName); + } + + @DataProvider + public static Object[][] data() { + return new Object[][]{ + {"refs/heads/default_branch_name", "default_branch_name"}, + {"refs/HEADS/default_branch_name", "default_branch_name"}, + {"refs/heads/Default_branch_name", "Default_branch_name"}, + {"branch_Name_without_prefix", "branch_Name_without_prefix"}, + {"", null}, + {null, null} + }; + } +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java index de7a2a6fc8b..ae2854cf85e 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectAction.java @@ -122,6 +122,7 @@ public class ImportAzureProjectAction implements AlmIntegrationsWsAction { ComponentDto componentDto = createProject(dbSession, repo); populatePRSetting(dbSession, repo, componentDto, almSettingDto); + componentUpdater.commitAndIndex(dbSession, componentDto); return toCreateResponse(componentDto); } @@ -129,13 +130,16 @@ public class ImportAzureProjectAction implements AlmIntegrationsWsAction { private ComponentDto createProject(DbSession dbSession, GsonAzureRepo repo) { boolean visibility = projectDefaultVisibility.get(dbSession).isPrivate(); - return componentUpdater.create(dbSession, newComponentBuilder() - .setKey(generateProjectKey(repo.getProject().getName(), repo.getName())) - .setName(repo.getName()) - .setPrivate(visibility) - .setQualifier(PROJECT) - .build(), - userSession.isLoggedIn() ? userSession.getUuid() : null); + return componentUpdater.createWithoutCommit(dbSession, newComponentBuilder() + .setKey(generateProjectKey(repo.getProject().getName(), repo.getName())) + .setName(repo.getName()) + .setPrivate(visibility) + .setQualifier(PROJECT) + .build(), + userSession.isLoggedIn() ? userSession.getUuid() : null, + repo.getDefaultBranchName(), + s -> { + }); } private void populatePRSetting(DbSession dbSession, GsonAzureRepo repo, ComponentDto componentDto, AlmSettingDto almSettingDto) { @@ -146,7 +150,6 @@ public class ImportAzureProjectAction implements AlmIntegrationsWsAction { .setProjectUuid(componentDto.uuid()) .setMonorepo(false); dbClient.projectAlmSettingDao().insertOrUpdate(dbSession, projectAlmSettingDto); - dbSession.commit(); } @VisibleForTesting diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionTest.java index 22b2439e197..710f2df4ac7 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionTest.java @@ -36,6 +36,7 @@ import org.sonar.db.DbTester; import org.sonar.db.alm.pat.AlmPatDto; import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto; +import org.sonar.db.component.BranchDto; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; import org.sonar.server.almintegration.ws.ImportHelper; @@ -114,10 +115,53 @@ public class ImportAzureProjectActionTest { Optional projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey()); assertThat(projectDto).isPresent(); + Optional projectAlmSettingDto = db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), projectDto.get()); assertThat(projectAlmSettingDto.get().getAlmRepo()).isEqualTo("repo-name"); assertThat(projectAlmSettingDto.get().getAlmSettingUuid()).isEqualTo(almSetting.getUuid()); assertThat(projectAlmSettingDto.get().getAlmSlug()).isEqualTo("project-name"); + + Optional mainBranch = db.getDbClient() + .branchDao() + .selectByProject(db.getSession(), projectDto.get()) + .stream() + .filter(BranchDto::isMain) + .findFirst(); + assertThat(mainBranch).isPresent(); + assertThat(mainBranch.get().getKey()).hasToString("repo-default-branch"); + } + + @Test + public void import_project_from_empty_repo() { + UserDto user = db.users().insertUser(); + userSession.logIn(user).addPermission(PROVISION_PROJECTS); + AlmSettingDto almSetting = db.almSettings().insertAzureAlmSetting(); + db.almPats().insert(dto -> { + dto.setAlmSettingUuid(almSetting.getUuid()); + dto.setPersonalAccessToken(almSetting.getPersonalAccessToken()); + dto.setUserUuid(user.getUuid()); + }); + GsonAzureRepo repo = getEmptyGsonAzureRepo(); + when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getPersonalAccessToken(), "project-name", "repo-name")) + .thenReturn(repo); + + Projects.CreateWsResponse response = ws.newRequest() + .setParam("almSetting", almSetting.getKey()) + .setParam("projectName", "project-name") + .setParam("repositoryName", "repo-name") + .executeProtobuf(Projects.CreateWsResponse.class); + + Projects.CreateWsResponse.Project result = response.getProject(); + Optional projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey()); + Optional mainBranch = db.getDbClient() + .branchDao() + .selectByProject(db.getSession(), projectDto.get()) + .stream() + .filter(BranchDto::isMain) + .findFirst(); + + assertThat(mainBranch).isPresent(); + assertThat(mainBranch.get().getKey()).hasToString("master"); } @Test @@ -232,7 +276,13 @@ public class ImportAzureProjectActionTest { private GsonAzureRepo getGsonAzureRepo() { return new GsonAzureRepo("repo-id", "repo-name", "repo-url", - new GsonAzureProject("project-name", "project-description")); + new GsonAzureProject("project-name", "project-description"), + "refs/heads/repo-default-branch"); + } + + private GsonAzureRepo getEmptyGsonAzureRepo() { + return new GsonAzureRepo("repo-id", "repo-name", "repo-url", + new GsonAzureProject("project-name", "project-description"), null); } } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionTest.java index ed736553046..5b01fc6062a 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionTest.java @@ -361,7 +361,7 @@ public class SearchAzureReposActionTest { private GsonAzureRepo getGsonAzureRepo(String projectName, String repoName) { GsonAzureProject project = new GsonAzureProject(projectName, "the best project ever"); - GsonAzureRepo gsonAzureRepo = new GsonAzureRepo("repo-id", repoName, "url", project); + GsonAzureRepo gsonAzureRepo = new GsonAzureRepo("repo-id", repoName, "url", project, "repo-default-branch"); return gsonAzureRepo; } } -- 2.39.5