@@ -0,0 +1,63 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2022 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 com.google.common.annotations.VisibleForTesting; | |||
import java.util.List; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.core.util.UuidFactory; | |||
import static com.google.common.collect.Lists.asList; | |||
import static org.sonar.core.component.ComponentKeys.sanitizeProjectKey; | |||
public class ProjectKeyGenerator { | |||
@VisibleForTesting | |||
static final int MAX_PROJECT_KEY_SIZE = 250; | |||
@VisibleForTesting | |||
static final Character PROJECT_KEY_SEPARATOR = '_'; | |||
private final UuidFactory uuidFactory; | |||
public ProjectKeyGenerator(UuidFactory uuidFactory) { | |||
this.uuidFactory = uuidFactory; | |||
} | |||
public String generateUniqueProjectKey(String projectName, String... extraProjectKeyItems) { | |||
String sqProjectKey = generateCompleteProjectKey(projectName, extraProjectKeyItems); | |||
sqProjectKey = truncateProjectKeyIfNecessary(sqProjectKey); | |||
return sanitizeProjectKey(sqProjectKey); | |||
} | |||
private String generateCompleteProjectKey(String projectName, String[] extraProjectKeyItems) { | |||
List<String> projectKeyItems = asList(projectName, extraProjectKeyItems); | |||
String projectKey = StringUtils.join(projectKeyItems, PROJECT_KEY_SEPARATOR); | |||
String uuid = uuidFactory.create(); | |||
return projectKey + PROJECT_KEY_SEPARATOR + uuid; | |||
} | |||
private static String truncateProjectKeyIfNecessary(String sqProjectKey) { | |||
if (sqProjectKey.length() > MAX_PROJECT_KEY_SIZE) { | |||
return sqProjectKey.substring(sqProjectKey.length() - MAX_PROJECT_KEY_SIZE); | |||
} | |||
return sqProjectKey; | |||
} | |||
} |
@@ -19,7 +19,6 @@ | |||
*/ | |||
package org.sonar.server.almintegration.ws.azure; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import java.util.Optional; | |||
import org.sonar.alm.client.azure.AzureDevOpsHttpClient; | |||
import org.sonar.alm.client.azure.GsonAzureRepo; | |||
@@ -34,6 +33,7 @@ import org.sonar.db.alm.setting.ProjectAlmSettingDto; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.server.almintegration.ws.AlmIntegrationsWsAction; | |||
import org.sonar.server.almintegration.ws.ImportHelper; | |||
import org.sonar.server.almintegration.ws.ProjectKeyGenerator; | |||
import org.sonar.server.component.ComponentUpdater; | |||
import org.sonar.server.project.ProjectDefaultVisibility; | |||
import org.sonar.server.user.UserSession; | |||
@@ -57,16 +57,18 @@ public class ImportAzureProjectAction implements AlmIntegrationsWsAction { | |||
private final ProjectDefaultVisibility projectDefaultVisibility; | |||
private final ComponentUpdater componentUpdater; | |||
private final ImportHelper importHelper; | |||
private final ProjectKeyGenerator projectKeyGenerator; | |||
public ImportAzureProjectAction(DbClient dbClient, UserSession userSession, AzureDevOpsHttpClient azureDevOpsHttpClient, | |||
ProjectDefaultVisibility projectDefaultVisibility, ComponentUpdater componentUpdater, | |||
ImportHelper importHelper) { | |||
ImportHelper importHelper, ProjectKeyGenerator projectKeyGenerator) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
this.azureDevOpsHttpClient = azureDevOpsHttpClient; | |||
this.projectDefaultVisibility = projectDefaultVisibility; | |||
this.componentUpdater = componentUpdater; | |||
this.importHelper = importHelper; | |||
this.projectKeyGenerator = projectKeyGenerator; | |||
} | |||
@Override | |||
@@ -128,8 +130,9 @@ public class ImportAzureProjectAction implements AlmIntegrationsWsAction { | |||
private ComponentDto createProject(DbSession dbSession, GsonAzureRepo repo) { | |||
boolean visibility = projectDefaultVisibility.get(dbSession).isPrivate(); | |||
String uniqueProjectKey = projectKeyGenerator.generateUniqueProjectKey(repo.getProject().getName(), repo.getName()); | |||
return componentUpdater.createWithoutCommit(dbSession, newComponentBuilder() | |||
.setKey(generateProjectKey(repo.getProject().getName(), repo.getName())) | |||
.setKey(uniqueProjectKey) | |||
.setName(repo.getName()) | |||
.setPrivate(visibility) | |||
.setQualifier(PROJECT) | |||
@@ -152,15 +155,4 @@ public class ImportAzureProjectAction implements AlmIntegrationsWsAction { | |||
componentDto.name(), componentDto.getKey()); | |||
} | |||
@VisibleForTesting | |||
String generateProjectKey(String projectName, String repoName) { | |||
String sqProjectKey = projectName + "_" + repoName; | |||
if (sqProjectKey.length() > 250) { | |||
sqProjectKey = sqProjectKey.substring(sqProjectKey.length() - 250); | |||
} | |||
return sqProjectKey.replace(" ", "_"); | |||
} | |||
} |
@@ -33,6 +33,7 @@ import org.sonar.db.alm.setting.ProjectAlmSettingDto; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.server.almintegration.ws.AlmIntegrationsWsAction; | |||
import org.sonar.server.almintegration.ws.ImportHelper; | |||
import org.sonar.server.almintegration.ws.ProjectKeyGenerator; | |||
import org.sonar.server.component.ComponentUpdater; | |||
import org.sonar.server.component.NewComponent; | |||
import org.sonar.server.project.ProjectDefaultVisibility; | |||
@@ -56,15 +57,18 @@ public class ImportBitbucketCloudRepoAction implements AlmIntegrationsWsAction { | |||
private final ProjectDefaultVisibility projectDefaultVisibility; | |||
private final ComponentUpdater componentUpdater; | |||
private final ImportHelper importHelper; | |||
private final ProjectKeyGenerator projectKeyGenerator; | |||
public ImportBitbucketCloudRepoAction(DbClient dbClient, UserSession userSession, BitbucketCloudRestClient bitbucketCloudRestClient, | |||
ProjectDefaultVisibility projectDefaultVisibility, ComponentUpdater componentUpdater, ImportHelper importHelper) { | |||
ProjectDefaultVisibility projectDefaultVisibility, ComponentUpdater componentUpdater, ImportHelper importHelper, | |||
ProjectKeyGenerator projectKeyGenerator) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
this.bitbucketCloudRestClient = bitbucketCloudRestClient; | |||
this.projectDefaultVisibility = projectDefaultVisibility; | |||
this.componentUpdater = componentUpdater; | |||
this.importHelper = importHelper; | |||
this.projectKeyGenerator = projectKeyGenerator; | |||
} | |||
@Override | |||
@@ -124,8 +128,9 @@ public class ImportBitbucketCloudRepoAction implements AlmIntegrationsWsAction { | |||
private ComponentDto createProject(DbSession dbSession, String workspace, Repository repo, @Nullable String defaultBranchName) { | |||
boolean visibility = projectDefaultVisibility.get(dbSession).isPrivate(); | |||
String uniqueProjectKey = projectKeyGenerator.generateUniqueProjectKey(workspace, repo.getSlug()); | |||
NewComponent newProject = newComponentBuilder() | |||
.setKey(workspace + "_" + repo.getSlug()) | |||
.setKey(uniqueProjectKey) | |||
.setName(repo.getName()) | |||
.setPrivate(visibility) | |||
.setQualifier(PROJECT) |
@@ -36,6 +36,7 @@ import org.sonar.db.alm.setting.ProjectAlmSettingDto; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.server.almintegration.ws.AlmIntegrationsWsAction; | |||
import org.sonar.server.almintegration.ws.ImportHelper; | |||
import org.sonar.server.almintegration.ws.ProjectKeyGenerator; | |||
import org.sonar.server.component.ComponentUpdater; | |||
import org.sonar.server.component.NewComponent; | |||
import org.sonar.server.project.ProjectDefaultVisibility; | |||
@@ -60,16 +61,18 @@ public class ImportBitbucketServerProjectAction implements AlmIntegrationsWsActi | |||
private final ProjectDefaultVisibility projectDefaultVisibility; | |||
private final ComponentUpdater componentUpdater; | |||
private final ImportHelper importHelper; | |||
private final ProjectKeyGenerator projectKeyGenerator; | |||
public ImportBitbucketServerProjectAction(DbClient dbClient, UserSession userSession, BitbucketServerRestClient bitbucketServerRestClient, | |||
ProjectDefaultVisibility projectDefaultVisibility, ComponentUpdater componentUpdater, | |||
ImportHelper importHelper) { | |||
ImportHelper importHelper, ProjectKeyGenerator projectKeyGenerator) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
this.bitbucketServerRestClient = bitbucketServerRestClient; | |||
this.projectDefaultVisibility = projectDefaultVisibility; | |||
this.componentUpdater = componentUpdater; | |||
this.importHelper = importHelper; | |||
this.projectKeyGenerator = projectKeyGenerator; | |||
} | |||
@Override | |||
@@ -141,8 +144,9 @@ public class ImportBitbucketServerProjectAction implements AlmIntegrationsWsActi | |||
private ComponentDto createProject(DbSession dbSession, Repository repo, @Nullable String defaultBranchName) { | |||
boolean visibility = projectDefaultVisibility.get(dbSession).isPrivate(); | |||
String uniqueProjectKey = projectKeyGenerator.generateUniqueProjectKey(repo.getProject().getKey(), repo.getSlug()); | |||
NewComponent newProject = newComponentBuilder() | |||
.setKey(getProjectKey(repo)) | |||
.setKey(uniqueProjectKey) | |||
.setName(repo.getName()) | |||
.setPrivate(visibility) | |||
.setQualifier(PROJECT) | |||
@@ -165,9 +169,4 @@ public class ImportBitbucketServerProjectAction implements AlmIntegrationsWsActi | |||
componentDto.name(), componentDto.getKey()); | |||
} | |||
private static String getProjectKey(Repository repo) { | |||
String key = repo.getProject().getKey() + "_" + repo.getSlug(); | |||
return key.replace("~", ""); | |||
} | |||
} |
@@ -35,6 +35,7 @@ import org.sonar.db.alm.setting.ProjectAlmSettingDto; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.server.almintegration.ws.AlmIntegrationsWsAction; | |||
import org.sonar.server.almintegration.ws.ImportHelper; | |||
import org.sonar.server.almintegration.ws.ProjectKeyGenerator; | |||
import org.sonar.server.component.ComponentUpdater; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.project.ProjectDefaultVisibility; | |||
@@ -59,15 +60,17 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction { | |||
private final GithubApplicationClient githubApplicationClient; | |||
private final ComponentUpdater componentUpdater; | |||
private final ImportHelper importHelper; | |||
private final ProjectKeyGenerator projectKeyGenerator; | |||
public ImportGithubProjectAction(DbClient dbClient, UserSession userSession, ProjectDefaultVisibility projectDefaultVisibility, | |||
GithubApplicationClientImpl githubApplicationClient, ComponentUpdater componentUpdater, ImportHelper importHelper) { | |||
GithubApplicationClientImpl githubApplicationClient, ComponentUpdater componentUpdater, ImportHelper importHelper, ProjectKeyGenerator projectKeyGenerator) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
this.projectDefaultVisibility = projectDefaultVisibility; | |||
this.githubApplicationClient = githubApplicationClient; | |||
this.componentUpdater = componentUpdater; | |||
this.importHelper = importHelper; | |||
this.projectKeyGenerator = projectKeyGenerator; | |||
} | |||
@Override | |||
@@ -131,19 +134,16 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction { | |||
private ComponentDto createProject(DbSession dbSession, Repository repo, String mainBranchName) { | |||
boolean visibility = projectDefaultVisibility.get(dbSession).isPrivate(); | |||
String uniqueProjectKey = projectKeyGenerator.generateUniqueProjectKey(repo.getFullName()); | |||
return componentUpdater.createWithoutCommit(dbSession, newComponentBuilder() | |||
.setKey(getProjectKeyFromRepository(repo)) | |||
.setName(repo.getName()) | |||
.setPrivate(visibility) | |||
.setQualifier(PROJECT) | |||
.build(), | |||
.setKey(uniqueProjectKey) | |||
.setName(repo.getName()) | |||
.setPrivate(visibility) | |||
.setQualifier(PROJECT) | |||
.build(), | |||
userSession.getUuid(), userSession.getLogin(), mainBranchName, s -> {}); | |||
} | |||
static String getProjectKeyFromRepository(Repository repo) { | |||
return repo.getFullName().replace("/", "_"); | |||
} | |||
private void populatePRSetting(DbSession dbSession, Repository repo, ComponentDto componentDto, AlmSettingDto almSettingDto) { | |||
ProjectAlmSettingDto projectAlmSettingDto = new ProjectAlmSettingDto() | |||
.setAlmSettingUuid(almSettingDto.getUuid()) |
@@ -19,7 +19,6 @@ | |||
*/ | |||
package org.sonar.server.almintegration.ws.gitlab; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import java.util.Optional; | |||
import javax.annotation.Nullable; | |||
import org.sonar.alm.client.gitlab.GitLabBranch; | |||
@@ -28,7 +27,6 @@ import org.sonar.alm.client.gitlab.Project; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.core.util.UuidFactory; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.alm.pat.AlmPatDto; | |||
@@ -37,6 +35,7 @@ import org.sonar.db.alm.setting.ProjectAlmSettingDto; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.server.almintegration.ws.AlmIntegrationsWsAction; | |||
import org.sonar.server.almintegration.ws.ImportHelper; | |||
import org.sonar.server.almintegration.ws.ProjectKeyGenerator; | |||
import org.sonar.server.component.ComponentUpdater; | |||
import org.sonar.server.project.ProjectDefaultVisibility; | |||
import org.sonar.server.user.UserSession; | |||
@@ -56,19 +55,19 @@ public class ImportGitLabProjectAction implements AlmIntegrationsWsAction { | |||
private final ProjectDefaultVisibility projectDefaultVisibility; | |||
private final GitlabHttpClient gitlabHttpClient; | |||
private final ComponentUpdater componentUpdater; | |||
private final UuidFactory uuidFactory; | |||
private final ImportHelper importHelper; | |||
private final ProjectKeyGenerator projectKeyGenerator; | |||
public ImportGitLabProjectAction(DbClient dbClient, UserSession userSession, | |||
ProjectDefaultVisibility projectDefaultVisibility, GitlabHttpClient gitlabHttpClient, | |||
ComponentUpdater componentUpdater, UuidFactory uuidFactory, ImportHelper importHelper) { | |||
ComponentUpdater componentUpdater, ImportHelper importHelper, ProjectKeyGenerator projectKeyGenerator) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
this.projectDefaultVisibility = projectDefaultVisibility; | |||
this.gitlabHttpClient = gitlabHttpClient; | |||
this.componentUpdater = componentUpdater; | |||
this.uuidFactory = uuidFactory; | |||
this.importHelper = importHelper; | |||
this.projectKeyGenerator = projectKeyGenerator; | |||
} | |||
@Override | |||
@@ -135,10 +134,10 @@ public class ImportGitLabProjectAction implements AlmIntegrationsWsAction { | |||
private ComponentDto createProject(DbSession dbSession, Project gitlabProject, @Nullable String mainBranchName) { | |||
boolean visibility = projectDefaultVisibility.get(dbSession).isPrivate(); | |||
String sqProjectKey = generateProjectKey(gitlabProject.getPathWithNamespace(), uuidFactory.create()); | |||
String uniqueProjectKey = projectKeyGenerator.generateUniqueProjectKey(gitlabProject.getPathWithNamespace()); | |||
return componentUpdater.createWithoutCommit(dbSession, newComponentBuilder() | |||
.setKey(sqProjectKey) | |||
.setKey(uniqueProjectKey) | |||
.setName(gitlabProject.getName()) | |||
.setPrivate(visibility) | |||
.setQualifier(PROJECT) | |||
@@ -147,14 +146,4 @@ public class ImportGitLabProjectAction implements AlmIntegrationsWsAction { | |||
}); | |||
} | |||
@VisibleForTesting | |||
String generateProjectKey(String pathWithNamespace, String uuid) { | |||
String sqProjectKey = pathWithNamespace + "_" + uuid; | |||
if (sqProjectKey.length() > 250) { | |||
sqProjectKey = sqProjectKey.substring(sqProjectKey.length() - 250); | |||
} | |||
return sqProjectKey.replace("/", "_"); | |||
} | |||
} |
@@ -24,8 +24,6 @@ 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; | |||
@@ -42,11 +40,6 @@ 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 | |||
@@ -55,7 +48,7 @@ public class ImportHelperTest { | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
private ImportHelper underTest = new ImportHelper(db.getDbClient(), userSession); | |||
private final ImportHelper underTest = new ImportHelper(db.getDbClient(), userSession); | |||
@Test | |||
public void it_throws_exception_when_provisioning_project_without_permission() { | |||
@@ -91,7 +84,7 @@ public class ImportHelperTest { | |||
CreateWsResponse.Project project = response.getProject(); | |||
assertThat(project).extracting(CreateWsResponse.Project::getKey, CreateWsResponse.Project::getName, | |||
CreateWsResponse.Project::getQualifier) | |||
CreateWsResponse.Project::getQualifier) | |||
.containsExactly(componentDto.getDbKey(), componentDto.name(), componentDto.qualifier()); | |||
} | |||
} |
@@ -0,0 +1,92 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2022 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.apache.commons.lang.RandomStringUtils; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import org.mockito.InjectMocks; | |||
import org.mockito.Mock; | |||
import org.mockito.junit.MockitoJUnitRunner; | |||
import org.sonar.core.util.UuidFactory; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.server.almintegration.ws.ProjectKeyGenerator.MAX_PROJECT_KEY_SIZE; | |||
import static org.sonar.server.almintegration.ws.ProjectKeyGenerator.PROJECT_KEY_SEPARATOR; | |||
@RunWith(MockitoJUnitRunner.class) | |||
public class ProjectKeyGeneratorTest { | |||
private static final int MAX_UUID_SIZE = 40; | |||
private static final String UUID_STRING = RandomStringUtils.randomAlphanumeric(MAX_UUID_SIZE); | |||
@Mock | |||
private UuidFactory uuidFactory; | |||
@InjectMocks | |||
private ProjectKeyGenerator projectKeyGenerator; | |||
@Before | |||
public void setUp() { | |||
when(uuidFactory.create()).thenReturn(UUID_STRING); | |||
} | |||
@Test | |||
public void generateUniqueProjectKey_shortProjectName_shouldAppendUuid() { | |||
String fullProjectName = RandomStringUtils.randomAlphanumeric(10); | |||
assertThat(projectKeyGenerator.generateUniqueProjectKey(fullProjectName)) | |||
.isEqualTo(generateExpectedKeyName(fullProjectName)); | |||
} | |||
@Test | |||
public void generateUniqueProjectKey_projectNameEqualsToMaximumSize_shouldTruncateProjectNameAndPreserveUUID() { | |||
String fullProjectName = RandomStringUtils.randomAlphanumeric(MAX_PROJECT_KEY_SIZE); | |||
String projectKey = projectKeyGenerator.generateUniqueProjectKey(fullProjectName); | |||
assertThat(projectKey) | |||
.hasSize(MAX_PROJECT_KEY_SIZE) | |||
.isEqualTo(generateExpectedKeyName(fullProjectName.substring(fullProjectName.length() + UUID_STRING.length() + 1 - MAX_PROJECT_KEY_SIZE))); | |||
} | |||
@Test | |||
public void generateUniqueProjectKey_projectNameBiggerThanMaximumSize_shouldTruncateProjectNameAndPreserveUUID() { | |||
String fullProjectName = RandomStringUtils.randomAlphanumeric(MAX_PROJECT_KEY_SIZE + 50); | |||
String projectKey = projectKeyGenerator.generateUniqueProjectKey(fullProjectName); | |||
assertThat(projectKey) | |||
.hasSize(MAX_PROJECT_KEY_SIZE) | |||
.isEqualTo(generateExpectedKeyName(fullProjectName.substring(fullProjectName.length() + UUID_STRING.length() + 1 - MAX_PROJECT_KEY_SIZE))); | |||
} | |||
@Test | |||
public void generateUniqueProjectKey_projectNameContainsSlashes_shouldBeEscaped() { | |||
String fullProjectName = "a/b/c"; | |||
assertThat(projectKeyGenerator.generateUniqueProjectKey(fullProjectName)) | |||
.isEqualTo(generateExpectedKeyName(fullProjectName.replace("/", "_"))); | |||
} | |||
private String generateExpectedKeyName(String truncatedProjectName) { | |||
return truncatedProjectName + PROJECT_KEY_SEPARATOR + UUID_STRING; | |||
} | |||
} |
@@ -20,8 +20,6 @@ | |||
package org.sonar.server.almintegration.ws.azure; | |||
import java.util.Optional; | |||
import java.util.stream.IntStream; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
@@ -41,6 +39,7 @@ 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; | |||
import org.sonar.server.almintegration.ws.ProjectKeyGenerator; | |||
import org.sonar.server.component.ComponentUpdater; | |||
import org.sonar.server.es.TestProjectIndexers; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
@@ -56,12 +55,12 @@ import org.sonar.server.ws.TestRequest; | |||
import org.sonar.server.ws.WsActionTester; | |||
import org.sonarqube.ws.Projects; | |||
import static java.util.stream.Collectors.joining; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.db.alm.integration.pat.AlmPatsTesting.newAlmPatDto; | |||
import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; | |||
@@ -69,6 +68,8 @@ import static org.sonar.db.permission.GlobalPermission.SCAN; | |||
public class ImportAzureProjectActionTest { | |||
private static final String GENERATED_PROJECT_KEY = "TEST_PROJECT_KEY"; | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
@Rule | |||
@@ -82,13 +83,15 @@ public class ImportAzureProjectActionTest { | |||
private final Encryption encryption = mock(Encryption.class); | |||
private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession); | |||
private final ProjectDefaultVisibility projectDefaultVisibility = mock(ProjectDefaultVisibility.class); | |||
private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class); | |||
private final ImportAzureProjectAction importAzureProjectAction = new ImportAzureProjectAction(db.getDbClient(), userSession, | |||
azureDevOpsHttpClient, projectDefaultVisibility, componentUpdater, importHelper); | |||
azureDevOpsHttpClient, projectDefaultVisibility, componentUpdater, importHelper, projectKeyGenerator); | |||
private final WsActionTester ws = new WsActionTester(importAzureProjectAction); | |||
@Before | |||
public void before() { | |||
when(projectDefaultVisibility.get(any())).thenReturn(Visibility.PRIVATE); | |||
when(projectKeyGenerator.generateUniqueProjectKey(any(), any())).thenReturn(GENERATED_PROJECT_KEY); | |||
} | |||
@Test | |||
@@ -113,7 +116,7 @@ public class ImportAzureProjectActionTest { | |||
.executeProtobuf(Projects.CreateWsResponse.class); | |||
Projects.CreateWsResponse.Project result = response.getProject(); | |||
assertThat(result.getKey()).isEqualTo(repo.getProject().getName() + "_" + repo.getName()); | |||
assertThat(result.getKey()).isEqualTo(GENERATED_PROJECT_KEY); | |||
assertThat(result.getName()).isEqualTo(repo.getName()); | |||
Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey()); | |||
@@ -132,6 +135,8 @@ public class ImportAzureProjectActionTest { | |||
.findFirst(); | |||
assertThat(mainBranch).isPresent(); | |||
assertThat(mainBranch.get().getKey()).hasToString("repo-default-branch"); | |||
verify(projectKeyGenerator).generateUniqueProjectKey(repo.getProject().getName(), repo.getName()); | |||
} | |||
@Test | |||
@@ -236,8 +241,7 @@ public class ImportAzureProjectActionTest { | |||
dto.setUserUuid(user.getUuid()); | |||
}); | |||
GsonAzureRepo repo = getGsonAzureRepo(); | |||
String projectKey = repo.getProject().getName() + "_" + repo.getName(); | |||
db.components().insertPublicProject(p -> p.setDbKey(projectKey)); | |||
db.components().insertPublicProject(p -> p.setDbKey(GENERATED_PROJECT_KEY)); | |||
when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getDecryptedPersonalAccessToken(encryption), | |||
"project-name", "repo-name")).thenReturn(repo); | |||
@@ -248,21 +252,7 @@ public class ImportAzureProjectActionTest { | |||
assertThatThrownBy(request::execute) | |||
.isInstanceOf(BadRequestException.class) | |||
.hasMessage("Could not create null, key already exists: " + projectKey); | |||
} | |||
@Test | |||
public void sanitize_project_and_repo_names_with_invalid_characters() { | |||
assertThat(importAzureProjectAction.generateProjectKey("project name", "repo name")) | |||
.isEqualTo("project_name_repo_name"); | |||
} | |||
@Test | |||
public void sanitize_long_project_and_repo_names() { | |||
String projectName = IntStream.range(0, 260).mapToObj(i -> "a").collect(joining()); | |||
assertThat(importAzureProjectAction.generateProjectKey(projectName, "repo name")) | |||
.hasSize(250); | |||
.hasMessage("Could not create null, key already exists: " + GENERATED_PROJECT_KEY); | |||
} | |||
@Test |
@@ -39,6 +39,7 @@ 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; | |||
import org.sonar.server.almintegration.ws.ProjectKeyGenerator; | |||
import org.sonar.server.component.ComponentUpdater; | |||
import org.sonar.server.es.TestProjectIndexers; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
@@ -54,17 +55,22 @@ import org.sonar.server.ws.TestRequest; | |||
import org.sonar.server.ws.WsActionTester; | |||
import org.sonarqube.ws.Projects; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.db.alm.integration.pat.AlmPatsTesting.newAlmPatDto; | |||
import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; | |||
import static org.sonar.db.permission.GlobalPermission.SCAN; | |||
public class ImportBitbucketCloudRepoActionTest { | |||
private static final String GENERATED_PROJECT_KEY = "TEST_PROJECT_KEY"; | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
@Rule | |||
@@ -77,12 +83,14 @@ public class ImportBitbucketCloudRepoActionTest { | |||
mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory()); | |||
private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession); | |||
private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class); | |||
private final WsActionTester ws = new WsActionTester(new ImportBitbucketCloudRepoAction(db.getDbClient(), userSession, | |||
bitbucketCloudRestClient, projectDefaultVisibility, componentUpdater, importHelper)); | |||
bitbucketCloudRestClient, projectDefaultVisibility, componentUpdater, importHelper, projectKeyGenerator)); | |||
@Before | |||
public void before() { | |||
when(projectDefaultVisibility.get(any())).thenReturn(Visibility.PRIVATE); | |||
when(projectKeyGenerator.generateUniqueProjectKey(any(), any())).thenReturn(GENERATED_PROJECT_KEY); | |||
} | |||
@Test | |||
@@ -103,7 +111,7 @@ public class ImportBitbucketCloudRepoActionTest { | |||
.executeProtobuf(Projects.CreateWsResponse.class); | |||
Projects.CreateWsResponse.Project result = response.getProject(); | |||
assertThat(result.getKey()).isEqualTo(almSetting.getAppId() + "_" + repo.getSlug()); | |||
assertThat(result.getKey()).isEqualTo(GENERATED_PROJECT_KEY); | |||
assertThat(result.getName()).isEqualTo(repo.getName()); | |||
Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey()); | |||
@@ -115,6 +123,7 @@ public class ImportBitbucketCloudRepoActionTest { | |||
Optional<BranchDto> branchDto = db.getDbClient().branchDao().selectByBranchKey(db.getSession(), projectDto.get().getUuid(), "develop"); | |||
assertThat(branchDto).isPresent(); | |||
assertThat(branchDto.get().isMain()).isTrue(); | |||
verify(projectKeyGenerator).generateUniqueProjectKey(requireNonNull(almSetting.getAppId()), repo.getSlug()); | |||
} | |||
@Test | |||
@@ -127,8 +136,7 @@ public class ImportBitbucketCloudRepoActionTest { | |||
dto.setUserUuid(user.getUuid()); | |||
}); | |||
Repository repo = getGsonBBCRepo(); | |||
String projectKey = almSetting.getAppId() + "_" + repo.getSlug(); | |||
db.components().insertPublicProject(p -> p.setDbKey(projectKey)); | |||
db.components().insertPublicProject(p -> p.setDbKey(GENERATED_PROJECT_KEY)); | |||
when(bitbucketCloudRestClient.getRepo(any(), any(), any())).thenReturn(repo); | |||
@@ -138,7 +146,7 @@ public class ImportBitbucketCloudRepoActionTest { | |||
assertThatThrownBy(request::execute) | |||
.isInstanceOf(BadRequestException.class) | |||
.hasMessageContaining("Could not create null, key already exists: " + projectKey); | |||
.hasMessageContaining("Could not create null, key already exists: " + GENERATED_PROJECT_KEY); | |||
} | |||
@Test |
@@ -44,6 +44,7 @@ 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; | |||
import org.sonar.server.almintegration.ws.ProjectKeyGenerator; | |||
import org.sonar.server.component.ComponentUpdater; | |||
import org.sonar.server.es.TestProjectIndexers; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
@@ -58,6 +59,7 @@ import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.ws.WsActionTester; | |||
import org.sonarqube.ws.Projects; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | |||
import static org.apache.commons.lang.math.JVMRandom.nextLong; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@@ -65,12 +67,14 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.db.alm.integration.pat.AlmPatsTesting.newAlmPatDto; | |||
import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; | |||
import static org.sonar.db.permission.GlobalPermission.SCAN; | |||
public class ImportBitbucketServerProjectActionTest { | |||
private static final String GENERATED_PROJECT_KEY = "TEST_PROJECT_KEY"; | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
@@ -84,8 +88,9 @@ public class ImportBitbucketServerProjectActionTest { | |||
mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory()); | |||
private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession); | |||
private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class); | |||
private final WsActionTester ws = new WsActionTester(new ImportBitbucketServerProjectAction(db.getDbClient(), userSession, | |||
bitbucketServerRestClient, projectDefaultVisibility, componentUpdater, importHelper)); | |||
bitbucketServerRestClient, projectDefaultVisibility, componentUpdater, importHelper, projectKeyGenerator)); | |||
private static BranchesList defaultBranchesList; | |||
@@ -98,6 +103,7 @@ public class ImportBitbucketServerProjectActionTest { | |||
@Before | |||
public void before() { | |||
when(projectDefaultVisibility.get(any())).thenReturn(Visibility.PRIVATE); | |||
when(projectKeyGenerator.generateUniqueProjectKey(any(), any())).thenReturn(GENERATED_PROJECT_KEY); | |||
} | |||
@Test | |||
@@ -121,40 +127,13 @@ public class ImportBitbucketServerProjectActionTest { | |||
.executeProtobuf(Projects.CreateWsResponse.class); | |||
Projects.CreateWsResponse.Project result = response.getProject(); | |||
assertThat(result.getKey()).isEqualTo(project.getKey() + "_" + repo.getSlug()); | |||
assertThat(result.getKey()).isEqualTo(GENERATED_PROJECT_KEY); | |||
assertThat(result.getName()).isEqualTo(repo.getName()); | |||
Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey()); | |||
assertThat(projectDto).isPresent(); | |||
assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), projectDto.get())).isPresent(); | |||
} | |||
@Test | |||
public void import_project_with_tilda() { | |||
UserDto user = db.users().insertUser(); | |||
userSession.logIn(user).addPermission(PROVISION_PROJECTS); | |||
AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting(); | |||
db.almPats().insert(dto -> { | |||
dto.setAlmSettingUuid(almSetting.getUuid()); | |||
dto.setUserUuid(user.getUuid()); | |||
}); | |||
Project project = getGsonBBSProject(); | |||
project.setKey("~" + project.getKey()); | |||
Repository repo = getGsonBBSRepo(project); | |||
when(bitbucketServerRestClient.getRepo(any(), any(), any(), any())).thenReturn(repo); | |||
when(bitbucketServerRestClient.getBranches(any(), any(), any(), any())).thenReturn(defaultBranchesList); | |||
Projects.CreateWsResponse response = ws.newRequest() | |||
.setParam("almSetting", almSetting.getKey()) | |||
.setParam("projectKey", "~projectKey") | |||
.setParam("repositorySlug", "repo-slug") | |||
.executeProtobuf(Projects.CreateWsResponse.class); | |||
Projects.CreateWsResponse.Project result = response.getProject(); | |||
String key = project.getKey() + "_" + repo.getSlug(); | |||
assertThat(result.getKey()).isNotEqualTo(key); | |||
assertThat(result.getKey()).isEqualTo(key.substring(1)); | |||
verify(projectKeyGenerator).generateUniqueProjectKey(requireNonNull(project.getKey()), repo.getSlug()); | |||
} | |||
@Test | |||
@@ -168,8 +147,7 @@ public class ImportBitbucketServerProjectActionTest { | |||
}); | |||
Project project = getGsonBBSProject(); | |||
Repository repo = getGsonBBSRepo(project); | |||
String projectKey = project.getKey() + "_" + repo.getSlug(); | |||
db.components().insertPublicProject(p -> p.setDbKey(projectKey)); | |||
db.components().insertPublicProject(p -> p.setDbKey(GENERATED_PROJECT_KEY)); | |||
assertThatThrownBy(() -> { | |||
when(bitbucketServerRestClient.getRepo(any(), any(), any(), any())).thenReturn(repo); | |||
@@ -182,7 +160,7 @@ public class ImportBitbucketServerProjectActionTest { | |||
.execute(); | |||
}) | |||
.isInstanceOf(BadRequestException.class) | |||
.hasMessage("Could not create null, key already exists: " + projectKey); | |||
.hasMessage("Could not create null, key already exists: " + GENERATED_PROJECT_KEY); | |||
} | |||
@Test |
@@ -36,9 +36,9 @@ import org.sonar.db.permission.GlobalPermission; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.server.almintegration.ws.ImportHelper; | |||
import org.sonar.server.almintegration.ws.ProjectKeyGenerator; | |||
import org.sonar.server.component.ComponentUpdater; | |||
import org.sonar.server.es.TestProjectIndexers; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.exceptions.UnauthorizedException; | |||
import org.sonar.server.favorite.FavoriteUpdater; | |||
@@ -63,6 +63,8 @@ import static org.sonar.server.tester.UserSessionRule.standalone; | |||
public class ImportGithubProjectActionTest { | |||
private static final String PROJECT_KEY_NAME = "PROJECT_NAME"; | |||
@Rule | |||
public UserSessionRule userSession = standalone(); | |||
@@ -76,9 +78,10 @@ public class ImportGithubProjectActionTest { | |||
mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory()); | |||
private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession); | |||
private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class); | |||
private final ProjectDefaultVisibility projectDefaultVisibility = mock(ProjectDefaultVisibility.class); | |||
private final WsActionTester ws = new WsActionTester(new ImportGithubProjectAction(db.getDbClient(), userSession, | |||
projectDefaultVisibility, appClient, componentUpdater, importHelper)); | |||
projectDefaultVisibility, appClient, componentUpdater, importHelper, projectKeyGenerator)); | |||
@Before | |||
public void before() { | |||
@@ -86,23 +89,23 @@ public class ImportGithubProjectActionTest { | |||
} | |||
@Test | |||
public void import_project() { | |||
public void importProject_ifProjectWithSameNameDoesNotExist_importSucceed() { | |||
AlmSettingDto githubAlmSetting = setupAlm(); | |||
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", "default-branch"); | |||
when(appClient.getRepository(any(), any(), any(), any())) | |||
.thenReturn(Optional.of(repository)); | |||
GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, PROJECT_KEY_NAME, false, "octocat/" + PROJECT_KEY_NAME, | |||
"https://github.sonarsource.com/api/v3/repos/octocat/" + PROJECT_KEY_NAME, "default-branch"); | |||
when(appClient.getRepository(any(), any(), any(), any())).thenReturn(Optional.of(repository)); | |||
when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn(PROJECT_KEY_NAME); | |||
Projects.CreateWsResponse response = ws.newRequest() | |||
.setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) | |||
.setParam(PARAM_ORGANIZATION, "octocat") | |||
.setParam(PARAM_REPOSITORY_KEY, "octocat/Hello-World") | |||
.setParam(PARAM_REPOSITORY_KEY, "octocat/" + PROJECT_KEY_NAME) | |||
.executeProtobuf(Projects.CreateWsResponse.class); | |||
Projects.CreateWsResponse.Project result = response.getProject(); | |||
assertThat(result.getKey()).isEqualTo(repository.getFullName().replace("/", "_")); | |||
assertThat(result.getKey()).isEqualTo(PROJECT_KEY_NAME); | |||
assertThat(result.getName()).isEqualTo(repository.getName()); | |||
Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey()); | |||
@@ -114,33 +117,35 @@ public class ImportGithubProjectActionTest { | |||
} | |||
@Test | |||
public void fail_project_already_exist() { | |||
public void importProject_ifProjectWithSameNameAlreadyExists_importSucceed() { | |||
AlmSettingDto githubAlmSetting = setupAlm(); | |||
db.almPats().insert(p -> p.setAlmSettingUuid(githubAlmSetting.getUuid()).setUserUuid(userSession.getUuid())); | |||
db.components().insertPublicProject(p -> p.setDbKey("octocat_Hello-World")); | |||
db.components().insertPublicProject(p -> p.setDbKey("Hello-World")); | |||
GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, "Hello-World", false, "octocat/Hello-World", | |||
GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, "Hello-World", false, "Hello-World", | |||
"https://github.sonarsource.com/api/v3/repos/octocat/Hello-World", "main"); | |||
when(appClient.getRepository(any(), any(), any(), any())) | |||
.thenReturn(Optional.of(repository)); | |||
when(appClient.getRepository(any(), any(), any(), any())).thenReturn(Optional.of(repository)); | |||
when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn(PROJECT_KEY_NAME); | |||
TestRequest request = ws.newRequest() | |||
.setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) | |||
.setParam(PARAM_ORGANIZATION, "octocat") | |||
.setParam(PARAM_REPOSITORY_KEY, "octocat/Hello-World"); | |||
assertThatThrownBy(request::execute) | |||
.isInstanceOf(BadRequestException.class) | |||
.hasMessage("Could not create null, key already exists: octocat_Hello-World"); | |||
Projects.CreateWsResponse response = ws.newRequest() | |||
.setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) | |||
.setParam(PARAM_ORGANIZATION, "octocat") | |||
.setParam(PARAM_REPOSITORY_KEY, "Hello-World") | |||
.executeProtobuf(Projects.CreateWsResponse.class); | |||
Projects.CreateWsResponse.Project result = response.getProject(); | |||
assertThat(result.getKey()).isEqualTo(PROJECT_KEY_NAME); | |||
assertThat(result.getName()).isEqualTo(repository.getName()); | |||
} | |||
@Test | |||
public void fail_when_not_logged_in() { | |||
TestRequest request = ws.newRequest() | |||
.setParam(PARAM_ALM_SETTING, "asdfghjkl") | |||
.setParam(PARAM_ORGANIZATION, "test") | |||
.setParam(PARAM_REPOSITORY_KEY, "test/repo"); | |||
.setParam(PARAM_ALM_SETTING, "asdfghjkl") | |||
.setParam(PARAM_ORGANIZATION, "test") | |||
.setParam(PARAM_REPOSITORY_KEY, "test/repo"); | |||
assertThatThrownBy(request::execute) | |||
.isInstanceOf(UnauthorizedException.class); | |||
.isInstanceOf(UnauthorizedException.class); | |||
} | |||
@Test | |||
@@ -156,12 +161,12 @@ public class ImportGithubProjectActionTest { | |||
userSession.logIn(user).addPermission(GlobalPermission.PROVISION_PROJECTS); | |||
TestRequest request = ws.newRequest() | |||
.setParam(PARAM_ALM_SETTING, "unknown") | |||
.setParam(PARAM_ORGANIZATION, "test") | |||
.setParam(PARAM_REPOSITORY_KEY, "test/repo"); | |||
.setParam(PARAM_ALM_SETTING, "unknown") | |||
.setParam(PARAM_ORGANIZATION, "test") | |||
.setParam(PARAM_REPOSITORY_KEY, "test/repo"); | |||
assertThatThrownBy(request::execute) | |||
.isInstanceOf(NotFoundException.class) | |||
.hasMessage("ALM Setting 'unknown' not found"); | |||
.isInstanceOf(NotFoundException.class) | |||
.hasMessage("ALM Setting 'unknown' not found"); | |||
} | |||
@Test | |||
@@ -169,12 +174,12 @@ public class ImportGithubProjectActionTest { | |||
AlmSettingDto githubAlmSetting = setupAlm(); | |||
TestRequest request = ws.newRequest() | |||
.setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) | |||
.setParam(PARAM_ORGANIZATION, "test") | |||
.setParam(PARAM_REPOSITORY_KEY, "test/repo"); | |||
.setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) | |||
.setParam(PARAM_ORGANIZATION, "test") | |||
.setParam(PARAM_REPOSITORY_KEY, "test/repo"); | |||
assertThatThrownBy(request::execute) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("No personal access token found"); | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("No personal access token found"); | |||
} | |||
@Test |
@@ -20,7 +20,6 @@ | |||
package org.sonar.server.almintegration.ws.gitlab; | |||
import java.util.Optional; | |||
import java.util.stream.IntStream; | |||
import org.assertj.core.api.Assertions; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
@@ -31,13 +30,13 @@ import org.sonar.alm.client.gitlab.Project; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.core.i18n.I18n; | |||
import org.sonar.core.util.SequenceUuidFactory; | |||
import org.sonar.core.util.UuidFactory; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.alm.setting.AlmSettingDto; | |||
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; | |||
import org.sonar.server.almintegration.ws.ProjectKeyGenerator; | |||
import org.sonar.server.component.ComponentUpdater; | |||
import org.sonar.server.es.TestProjectIndexers; | |||
import org.sonar.server.favorite.FavoriteUpdater; | |||
@@ -50,7 +49,6 @@ import org.sonarqube.ws.Projects; | |||
import static java.util.Collections.emptyList; | |||
import static java.util.Collections.singletonList; | |||
import static java.util.stream.Collectors.joining; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
@@ -63,6 +61,8 @@ import static org.sonar.server.tester.UserSessionRule.standalone; | |||
public class ImportGitLabProjectActionTest { | |||
private static final String PROJECT_KEY_NAME = "PROJECT_NAME"; | |||
private final System2 system2 = mock(System2.class); | |||
@Rule | |||
@@ -75,11 +75,11 @@ public class ImportGitLabProjectActionTest { | |||
mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory()); | |||
private final GitlabHttpClient gitlabHttpClient = mock(GitlabHttpClient.class); | |||
private final UuidFactory uuidFactory = mock(UuidFactory.class); | |||
private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession); | |||
private final ProjectDefaultVisibility projectDefaultVisibility = mock(ProjectDefaultVisibility.class); | |||
private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class); | |||
private final ImportGitLabProjectAction importGitLabProjectAction = new ImportGitLabProjectAction( | |||
db.getDbClient(), userSession, projectDefaultVisibility, gitlabHttpClient, componentUpdater, uuidFactory, importHelper); | |||
db.getDbClient(), userSession, projectDefaultVisibility, gitlabHttpClient, componentUpdater, importHelper, projectKeyGenerator); | |||
private final WsActionTester ws = new WsActionTester(importGitLabProjectAction); | |||
@Before | |||
@@ -100,7 +100,7 @@ public class ImportGitLabProjectActionTest { | |||
Project project = getGitlabProject(); | |||
when(gitlabHttpClient.getProject(any(), any(), any())).thenReturn(project); | |||
when(gitlabHttpClient.getBranches(any(), any(), any())).thenReturn(singletonList(new GitLabBranch("master", true))); | |||
when(uuidFactory.create()).thenReturn("uuid"); | |||
when(projectKeyGenerator.generateUniqueProjectKey(project.getPathWithNamespace())).thenReturn(PROJECT_KEY_NAME); | |||
Projects.CreateWsResponse response = ws.newRequest() | |||
.setParam("almSetting", almSetting.getKey()) | |||
@@ -110,7 +110,7 @@ public class ImportGitLabProjectActionTest { | |||
verify(gitlabHttpClient).getProject(almSetting.getUrl(), "PAT", 12345L); | |||
Projects.CreateWsResponse.Project result = response.getProject(); | |||
assertThat(result.getKey()).isEqualTo(project.getPathWithNamespace() + "_uuid"); | |||
assertThat(result.getKey()).isEqualTo(PROJECT_KEY_NAME); | |||
assertThat(result.getName()).isEqualTo(project.getName()); | |||
Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey()); | |||
@@ -131,7 +131,7 @@ public class ImportGitLabProjectActionTest { | |||
Project project = getGitlabProject(); | |||
when(gitlabHttpClient.getProject(any(), any(), any())).thenReturn(project); | |||
when(gitlabHttpClient.getBranches(any(), any(), any())).thenReturn(singletonList(new GitLabBranch("main", true))); | |||
when(uuidFactory.create()).thenReturn("uuid"); | |||
when(projectKeyGenerator.generateUniqueProjectKey(project.getPathWithNamespace())).thenReturn(PROJECT_KEY_NAME); | |||
Projects.CreateWsResponse response = ws.newRequest() | |||
.setParam("almSetting", almSetting.getKey()) | |||
@@ -142,7 +142,7 @@ public class ImportGitLabProjectActionTest { | |||
verify(gitlabHttpClient).getBranches(almSetting.getUrl(), "PAT", 12345L); | |||
Projects.CreateWsResponse.Project result = response.getProject(); | |||
assertThat(result.getKey()).isEqualTo(project.getPathWithNamespace() + "_uuid"); | |||
assertThat(result.getKey()).isEqualTo(PROJECT_KEY_NAME); | |||
assertThat(result.getName()).isEqualTo(project.getName()); | |||
Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey()); | |||
@@ -167,7 +167,7 @@ public class ImportGitLabProjectActionTest { | |||
Project project = getGitlabProject(); | |||
when(gitlabHttpClient.getProject(any(), any(), any())).thenReturn(project); | |||
when(gitlabHttpClient.getBranches(any(), any(), any())).thenReturn(emptyList()); | |||
when(uuidFactory.create()).thenReturn("uuid"); | |||
when(projectKeyGenerator.generateUniqueProjectKey(project.getPathWithNamespace())).thenReturn(PROJECT_KEY_NAME); | |||
Projects.CreateWsResponse response = ws.newRequest() | |||
.setParam("almSetting", almSetting.getKey()) | |||
@@ -178,7 +178,7 @@ public class ImportGitLabProjectActionTest { | |||
verify(gitlabHttpClient).getBranches(almSetting.getUrl(), "PAT", 12345L); | |||
Projects.CreateWsResponse.Project result = response.getProject(); | |||
assertThat(result.getKey()).isEqualTo(project.getPathWithNamespace() + "_uuid"); | |||
assertThat(result.getKey()).isEqualTo(PROJECT_KEY_NAME); | |||
assertThat(result.getName()).isEqualTo(project.getName()); | |||
Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey()); | |||
@@ -190,36 +190,6 @@ public class ImportGitLabProjectActionTest { | |||
.containsExactlyInAnyOrder(tuple("master", true)); | |||
} | |||
@Test | |||
public void generate_project_key_less_than_250() { | |||
String name = "abcdeert"; | |||
assertThat(importGitLabProjectAction.generateProjectKey(name, "uuid")).isEqualTo("abcdeert_uuid"); | |||
} | |||
@Test | |||
public void generate_project_key_equal_250() { | |||
String name = IntStream.range(0, 245).mapToObj(i -> "a").collect(joining()); | |||
String projectKey = importGitLabProjectAction.generateProjectKey(name, "uuid"); | |||
assertThat(projectKey) | |||
.hasSize(250) | |||
.isEqualTo(name + "_uuid"); | |||
} | |||
@Test | |||
public void generate_project_key_more_than_250() { | |||
String name = IntStream.range(0, 250).mapToObj(i -> "a").collect(joining()); | |||
String projectKey = importGitLabProjectAction.generateProjectKey(name, "uuid"); | |||
assertThat(projectKey) | |||
.hasSize(250) | |||
.isEqualTo(name.substring(5) + "_uuid"); | |||
} | |||
@Test | |||
public void generate_project_key_containing_slash() { | |||
String name = "a/b/c"; | |||
assertThat(importGitLabProjectAction.generateProjectKey(name, "uuid")).isEqualTo("a_b_c_uuid"); | |||
} | |||
private Project getGitlabProject() { | |||
return new Project(randomAlphanumeric(5), randomAlphanumeric(5)); |
@@ -56,6 +56,7 @@ import org.sonar.core.platform.SpringComponentContainer; | |||
import org.sonar.server.almintegration.ws.AlmIntegrationsWSModule; | |||
import org.sonar.server.almintegration.ws.CredentialsEncoderHelper; | |||
import org.sonar.server.almintegration.ws.ImportHelper; | |||
import org.sonar.server.almintegration.ws.ProjectKeyGenerator; | |||
import org.sonar.server.almsettings.MultipleAlmFeatureProvider; | |||
import org.sonar.server.almsettings.ws.AlmSettingsWsModule; | |||
import org.sonar.server.authentication.AuthenticationModule; | |||
@@ -526,6 +527,7 @@ public class PlatformLevel4 extends PlatformLevel { | |||
TimeoutConfigurationImpl.class, | |||
CredentialsEncoderHelper.class, | |||
ImportHelper.class, | |||
ProjectKeyGenerator.class, | |||
GithubAppSecurityImpl.class, | |||
GithubApplicationClientImpl.class, | |||
GithubApplicationHttpClientImpl.class, |
@@ -34,11 +34,19 @@ public final class ComponentKeys { | |||
public static final String MALFORMED_KEY_MESSAGE = "Malformed key for '%s'. %s."; | |||
/** | |||
* Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit | |||
* Allowed characters are alphanumeric, '-', '_', '.' and ':' | |||
*/ | |||
private static final Pattern VALID_PROJECT_KEY_REGEXP = Pattern.compile("[\\p{Alnum}\\-_.:]*[\\p{Alpha}\\-_.:]+[\\p{Alnum}\\-_.:]*"); | |||
private static final String VALID_PROJECT_KEY_CHARS = "\\p{Alnum}-_.:"; | |||
private static final Pattern INVALID_PROJECT_KEY_REGEXP = Pattern.compile("[^" + VALID_PROJECT_KEY_CHARS + "]"); | |||
/** | |||
* At least one non-digit is necessary | |||
*/ | |||
private static final Pattern VALID_PROJECT_KEY_REGEXP = Pattern.compile("[" + VALID_PROJECT_KEY_CHARS + "]*[\\p{Alpha}\\-_.:]+[" + VALID_PROJECT_KEY_CHARS + "]*"); | |||
private static final String KEY_WITH_BRANCH_FORMAT = "%s:%s"; | |||
private static final String REPLACEMENT_CHARACTER = "_"; | |||
private ComponentKeys() { | |||
// only static stuff | |||
@@ -66,6 +74,10 @@ public final class ComponentKeys { | |||
checkArgument(isValidProjectKey(keyCandidate), MALFORMED_KEY_MESSAGE, keyCandidate, ALLOWED_CHARACTERS_MESSAGE); | |||
} | |||
public static String sanitizeProjectKey(String rawProjectKey) { | |||
return INVALID_PROJECT_KEY_REGEXP.matcher(rawProjectKey).replaceAll(REPLACEMENT_CHARACTER); | |||
} | |||
/** | |||
* Return the project key with potential branch | |||
*/ |
@@ -0,0 +1,57 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2022 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.core.component; | |||
import java.util.Arrays; | |||
import java.util.Collection; | |||
import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import org.junit.runners.Parameterized; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@RunWith(Parameterized.class) | |||
public class ComponentKeysSanitizationTest { | |||
@Parameterized.Parameters(name = "{index}: input {0}, expected output {1}") | |||
public static Collection<String[]> data() { | |||
return Arrays.asList(new String[][] { | |||
{"/a/b/c/", "_a_b_c_"}, | |||
{".a.b:c:", ".a.b:c:"}, | |||
{"_1_2_3_", "_1_2_3_"}, | |||
{"fully_valid_-name2", "fully_valid_-name2"}, | |||
{"°+\"*ç%&\\/()=?`^“#Ç[]|{}≠¿ ~", "___________________________"}, | |||
}); | |||
} | |||
private final String inputString; | |||
private final String expectedOutputString; | |||
public ComponentKeysSanitizationTest(String inputString, String expectedOutputString) { | |||
this.inputString = inputString; | |||
this.expectedOutputString = expectedOutputString; | |||
} | |||
@Test | |||
public void sanitizeProjectKey() { | |||
assertThat(ComponentKeys.sanitizeProjectKey(inputString)).isEqualTo(expectedOutputString); | |||
} | |||
} |