From: Simon Brandhof Date: Thu, 29 Mar 2018 15:09:18 +0000 (+0200) Subject: SONAR-10511 Project key renaming should rename deleted components too X-Git-Tag: 7.5~1401 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=492942631b3c2612fd8ed9b03bd7db3261a38e58;p=sonarqube.git SONAR-10511 Project key renaming should rename deleted components too --- diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java index a83a1849105..6a0ea848516 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java @@ -83,7 +83,7 @@ public class ComponentKeyUpdaterDao implements Dao { * @return a map with currentKey/newKey is a bulk update was executed */ public Map simulateBulkUpdateKey(DbSession dbSession, String projectUuid, String stringToReplace, String replacementString) { - return collectAllModules(projectUuid, stringToReplace, mapper(dbSession)) + return collectAllModules(projectUuid, stringToReplace, mapper(dbSession), false) .stream() .collect(Collectors.toMap( ResourceDto::getKey, @@ -109,7 +109,7 @@ public class ComponentKeyUpdaterDao implements Dao { public void bulkUpdateKey(DbSession session, String projectUuid, String stringToReplace, String replacementString) { ComponentKeyUpdaterMapper mapper = session.getMapper(ComponentKeyUpdaterMapper.class); // must SELECT first everything - Set modules = collectAllModules(projectUuid, stringToReplace, mapper); + Set modules = collectAllModules(projectUuid, stringToReplace, mapper, true); checkNewNameOfAllModules(modules, stringToReplace, replacementString, mapper); // add branches (no check should be done as branch keys cannot be changed by the user) @@ -118,7 +118,7 @@ public class ComponentKeyUpdaterDao implements Dao { .stream() .filter(branch -> !projectUuid.equals(branch.getUuid())) .forEach(branch -> { - Set branchModules = collectAllModules(branch.getUuid(), stringToReplace, mapper); + Set branchModules = collectAllModules(branch.getUuid(), stringToReplace, mapper, true); modules.addAll(branchModules); branchModules.forEach(module -> branchBaseKeys.put(module.getKey(), branchBaseKey(module.getKey()))); }); @@ -165,14 +165,14 @@ public class ComponentKeyUpdaterDao implements Dao { } } - private static Set collectAllModules(String projectUuid, String stringToReplace, ComponentKeyUpdaterMapper mapper) { + private static Set collectAllModules(String projectUuid, String stringToReplace, ComponentKeyUpdaterMapper mapper, boolean includeDisabled) { ResourceDto project = mapper.selectProject(projectUuid); Set modules = new HashSet<>(); - if (project.getKey().contains(stringToReplace)) { + if (project.getKey().contains(stringToReplace) && (project.isEnabled() || includeDisabled)) { modules.add(project); } for (ResourceDto submodule : mapper.selectDescendantProjects(projectUuid)) { - modules.addAll(collectAllModules(submodule.getUuid(), stringToReplace, mapper)); + modules.addAll(collectAllModules(submodule.getUuid(), stringToReplace, mapper, includeDisabled)); } return modules; } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentKeyUpdaterMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentKeyUpdaterMapper.xml index d7189fdb1ec..51f2114ab66 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentKeyUpdaterMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentKeyUpdaterMapper.xml @@ -29,7 +29,6 @@ where root_uuid = #{rootUuid,jdbcType=VARCHAR} and scope != 'PRJ' - and enabled = ${_true} diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentKeyUpdaterDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentKeyUpdaterDaoTest.java index 2e39482e656..b7f4e9cf381 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentKeyUpdaterDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentKeyUpdaterDaoTest.java @@ -63,7 +63,7 @@ public class ComponentKeyUpdaterDaoTest { } @Test - public void updateKey_does_not_update_inactive_components() { + public void updateKey_updates_disabled_components() { OrganizationDto organizationDto = db.organizations().insert(); ComponentDto project = db.components().insertComponent(newPrivateProjectDto(organizationDto, "A").setDbKey("my_project")); ComponentDto directory = db.components().insertComponent(newDirectory(project, "/directory").setDbKey("my_project:directory")); @@ -75,8 +75,10 @@ public class ComponentKeyUpdaterDaoTest { dbSession.commit(); List result = dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, "your_project"); - assertThat(result).hasSize(5).extracting(ComponentDto::getDbKey) - .containsOnlyOnce("your_project", "your_project:directory", "your_project:directory/file", "my_project:inactive_directory", "my_project:inactive_directory/file"); + assertThat(result) + .hasSize(5) + .extracting(ComponentDto::getDbKey) + .containsOnlyOnce("your_project", "your_project:directory", "your_project:directory/file", "your_project:inactive_directory", "your_project:inactive_directory/file"); } @Test @@ -216,7 +218,7 @@ public class ComponentKeyUpdaterDaoTest { } @Test - public void bulk_update_key_does_not_update_inactive_components() { + public void bulk_update_key_updates_disabled_components() { ComponentDto project = db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization(), "A").setDbKey("my_project")); db.components().insertComponent(newModuleDto(project).setDbKey("my_project:module")); db.components().insertComponent(newModuleDto(project).setDbKey("my_project:inactive_module").setEnabled(false)); @@ -224,8 +226,10 @@ public class ComponentKeyUpdaterDaoTest { underTest.bulkUpdateKey(dbSession, "A", "my_", "your_"); List result = dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, "your_project"); - assertThat(result).hasSize(3).extracting(ComponentDto::getDbKey) - .containsOnlyOnce("your_project", "your_project:module", "my_project:inactive_module"); + assertThat(result) + .hasSize(3) + .extracting(ComponentDto::getDbKey) + .containsOnlyOnce("your_project", "your_project:module", "your_project:inactive_module"); } @Test @@ -328,16 +332,17 @@ public class ComponentKeyUpdaterDaoTest { } @Test - public void simulate_bulk_update_key_do_not_return_disable_components() { + public void simulate_bulk_update_key_does_not_return_disable_components() { ComponentDto project = db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization(), "A").setDbKey("project")); db.components().insertComponent(newModuleDto(project).setDbKey("project:enabled-module")); db.components().insertComponent(newModuleDto(project).setDbKey("project:disabled-module").setEnabled(false)); + db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization(), "D").setDbKey("other-project")); Map result = underTest.simulateBulkUpdateKey(dbSession, "A", "project", "new-project"); - assertThat(result) - .hasSize(2) - .containsOnly(entry("project", "new-project"), entry("project:enabled-module", "new-project:enabled-module")); + assertThat(result).containsOnly( + entry("project", "new-project"), + entry("project:enabled-module", "new-project:enabled-module")); } @Test diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/ProjectTester.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/ProjectTester.java index 6cf912f2f32..21443871a10 100644 --- a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/ProjectTester.java +++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/ProjectTester.java @@ -22,8 +22,11 @@ package org.sonarqube.qa.util; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import javax.annotation.Nullable; +import org.sonarqube.ws.Components; import org.sonarqube.ws.Organizations; import org.sonarqube.ws.Projects; +import org.sonarqube.ws.client.HttpException; +import org.sonarqube.ws.client.components.ShowRequest; import org.sonarqube.ws.client.projects.CreateRequest; import org.sonarqube.ws.client.projects.DeleteRequest; import org.sonarqube.ws.client.projects.ProjectsService; @@ -64,4 +67,16 @@ public class ProjectTester { return session.wsClient().projects().create(request).getProject(); } + + public boolean exists(String projectKey) { + try { + Components.ShowWsResponse response = session.wsClient().components().show(new ShowRequest().setComponent(projectKey)); + return response.getComponent() != null; + } catch (HttpException e) { + if (e.code() == 404) { + return false; + } + throw new IllegalStateException(e); + } + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceTest.java index b1162d21da9..bd5c5740a3a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceTest.java @@ -65,8 +65,8 @@ public class ComponentServiceTest { assertComponentKeyUpdated(project.getDbKey(), "your_project"); assertComponentKeyUpdated(module.getDbKey(), "your_project:root:module"); assertComponentKeyUpdated(file.getDbKey(), "your_project:root:module:src/File.xoo"); - assertComponentKeyNotUpdated(inactiveModule.getDbKey()); - assertComponentKeyNotUpdated(inactiveFile.getDbKey()); + assertComponentKeyUpdated(inactiveModule.getDbKey(), "your_project:root:inactive_module"); + assertComponentKeyUpdated(inactiveFile.getDbKey(), "your_project:root:module:src/InactiveFile.xoo"); } private void assertComponentKeyUpdated(String oldKey, String newKey) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceUpdateKeyTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceUpdateKeyTest.java index 0d5b8a0a019..f8932006235 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceUpdateKeyTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceUpdateKeyTest.java @@ -76,8 +76,9 @@ public class ComponentServiceUpdateKeyTest { // Check file key has been updated assertThat(db.getDbClient().componentDao().selectByKey(dbSession, file.getDbKey())).isAbsent(); assertThat(db.getDbClient().componentDao().selectByKey(dbSession, "sample2:root:src/File.xoo")).isNotNull(); + assertThat(db.getDbClient().componentDao().selectByKey(dbSession, "sample2:root:src/InactiveFile.xoo")).isNotNull(); - assertThat(dbClient.componentDao().selectByKey(dbSession, inactiveFile.getDbKey())).isPresent(); + assertThat(dbClient.componentDao().selectByKey(dbSession, inactiveFile.getDbKey())).isAbsent(); org.assertj.core.api.Assertions.assertThat(projectIndexers.hasBeenCalled(project.uuid(), ProjectIndexer.Cause.PROJECT_KEY_UPDATE)).isTrue(); } @@ -185,8 +186,8 @@ public class ComponentServiceUpdateKeyTest { assertComponentKeyUpdated(project.getDbKey(), "your_project"); assertComponentKeyUpdated(module.getDbKey(), "your_project:root:module"); assertComponentKeyUpdated(file.getDbKey(), "your_project:root:module:src/File.xoo"); - assertComponentKeyNotUpdated(inactiveModule.getDbKey()); - assertComponentKeyNotUpdated(inactiveFile.getDbKey()); + assertComponentKeyUpdated(inactiveModule.getDbKey(), "your_project:root:inactive_module"); + assertComponentKeyUpdated(inactiveFile.getDbKey(), "your_project:root:module:src/InactiveFile.xoo"); } private void assertComponentKeyUpdated(String oldKey, String newKey) { @@ -194,10 +195,6 @@ public class ComponentServiceUpdateKeyTest { assertThat(dbClient.componentDao().selectByKey(dbSession, newKey)).isPresent(); } - private void assertComponentKeyNotUpdated(String key) { - assertThat(dbClient.componentDao().selectByKey(dbSession, key)).isPresent(); - } - private ComponentDto insertSampleRootProject() { return insertProject("sample:root"); } diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectKeyUpdateTest.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectKeyUpdateTest.java index f77c1d4fb9d..d4f004dd9f1 100644 --- a/tests/src/test/java/org/sonarqube/tests/project/ProjectKeyUpdateTest.java +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectKeyUpdateTest.java @@ -21,31 +21,43 @@ package org.sonarqube.tests.project; import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.build.SonarScanner; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Properties; import java.util.stream.Collectors; import javax.annotation.CheckForNull; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; import org.junit.After; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.DisableOnDebug; +import org.junit.rules.TemporaryFolder; import org.junit.rules.TestRule; import org.junit.rules.Timeout; import org.sonarqube.qa.util.Tester; import org.sonarqube.ws.Components; import org.sonarqube.ws.Organizations; import org.sonarqube.ws.Projects; +import org.sonarqube.ws.Projects.BulkUpdateKeyWsResponse.Key; import org.sonarqube.ws.client.GetRequest; import org.sonarqube.ws.client.WsResponse; import org.sonarqube.ws.client.components.SearchProjectsRequest; import org.sonarqube.ws.client.components.ShowRequest; +import org.sonarqube.ws.client.components.TreeRequest; +import org.sonarqube.ws.client.projects.BulkUpdateKeyRequest; import org.sonarqube.ws.client.projects.UpdateKeyRequest; -import org.sonarqube.ws.client.projects.CreateRequest; import util.ItUtils; +import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.groups.Tuple.tuple; import static util.ItUtils.projectDir; public class ProjectKeyUpdateTest { @@ -57,7 +69,8 @@ public class ProjectKeyUpdateTest { @Rule public TestRule safeguard = new DisableOnDebug(Timeout.seconds(300)); - + @Rule + public TemporaryFolder temp = new TemporaryFolder(); @Rule public Tester tester = new Tester(orchestrator).setElasticsearchHttpPort(ProjectSuite.SEARCH_HTTP_PORT); @@ -67,17 +80,18 @@ public class ProjectKeyUpdateTest { } @Test - public void update_key() { - analyzeXooSample(); - String newProjectKey = "another_project_key"; - Components.Component project = tester.wsClient().components().show(new ShowRequest().setComponent(PROJECT_KEY)).getComponent(); - assertThat(project.getKey()).isEqualTo(PROJECT_KEY); + public void update_key() throws IOException { + Organizations.Organization organization = tester.organizations().generate(); + File projectDir = new XooProjectBuilder(PROJECT_KEY) + .build(temp.newFolder()); + analyze(organization, projectDir); + assertThat(tester.projects().exists(PROJECT_KEY)).isTrue(); - tester.wsClient().projects().updateKey(new UpdateKeyRequest() - .setFrom(PROJECT_KEY) - .setTo(newProjectKey)); + String newProjectKey = "renamed"; + updateProjectKey(PROJECT_KEY, newProjectKey, false); - assertThat(tester.wsClient().components().show(new ShowRequest().setComponentId(project.getId())).getComponent().getKey()).isEqualTo(newProjectKey); + assertThat(tester.projects().exists(PROJECT_KEY)).isFalse(); + assertThat(tester.projects().exists(newProjectKey)).isTrue(); } @Test @@ -85,7 +99,7 @@ public class ProjectKeyUpdateTest { Organizations.Organization organization = tester.organizations().generate(); Projects.CreateWsResponse.Project project = createProject(organization, "one", "Foo"); - updateKey(project, "two"); + updateProjectKey(project.getKey(), "two", false); assertThat(isProjectInDatabase("one")).isFalse(); assertThat(isProjectInDatabase("two")).isTrue(); @@ -102,7 +116,7 @@ public class ProjectKeyUpdateTest { lockWritesOnProjectIndices(); - updateKey(project, "two"); + updateProjectKey(project.getKey(), "two", false); assertThat(isProjectInDatabase("one")).isFalse(); @@ -142,7 +156,7 @@ public class ProjectKeyUpdateTest { String initialKey = "com.sonarsource.it.samples:multi-modules-sample:module_a"; String newKey = "com.sonarsource.it.samples:multi-modules-sample:module_c"; - updateKey(initialKey, newKey); + updateModuleKey(initialKey, newKey); assertThat(isComponentInDatabase(initialKey)).isFalse(); assertThat(isComponentInDatabase(newKey)).isTrue(); @@ -168,7 +182,7 @@ public class ProjectKeyUpdateTest { String newKey = "com.sonarsource.it.samples:multi-modules-sample:module_c"; lockWritesOnProjectIndices(); - updateKey(initialKey, newKey); + updateModuleKey(initialKey, newKey); // api/components/search loads keys from db, so results are consistent assertThat(isComponentInDatabase(initialKey)).isFalse(); @@ -193,7 +207,133 @@ public class ProjectKeyUpdateTest { Thread.sleep(1_000L); recovered = keysInComponentSuggestions(newKey).contains(newKey) && keysInComponentSuggestions(initialKey).isEmpty(); } + } + + /** + * SONAR-10511 + */ + @Test + public void update_key_of_disabled_files() throws Exception { + Organizations.Organization organization = tester.organizations().generate(); + // first analysis + File projectWith2Files = new XooProjectBuilder(PROJECT_KEY) + .setFilesPerModule(2) + .build(temp.newFolder()); + analyze(organization, projectWith2Files); + assertThat(countFilesInProject()).isEqualTo(2); + + // second analysis emulates a deletion of file + File projectWith1File = new XooProjectBuilder(PROJECT_KEY) + .setFilesPerModule(1) + .build(temp.newFolder()); + analyze(organization, projectWith1File); + assertThat(countFilesInProject()).isEqualTo(1); + + // update the project key + updateProjectKey(PROJECT_KEY, "renamed", false); + ItUtils.expectNotFoundError(() -> tester.wsClient().components().show(new ShowRequest().setComponent(PROJECT_KEY))); + + // first analysis of the new project, which re-enables the deleted file + analyze(organization, projectWith2Files); + assertThat(countFilesInProject()).isEqualTo(2); + } + + /** + * SONAR-10511 + */ + @Test + public void update_of_project_key_includes_disabled_modules() throws Exception { + Organizations.Organization organization = tester.organizations().generate(); + + // first analysis + File projectWithModulesAB = new XooProjectBuilder(PROJECT_KEY) + .addModules("module_a", "module_b") + .build(temp.newFolder()); + analyze(organization, projectWithModulesAB); + assertThat(countFilesInProject()).isEqualTo(3); + + // second analysis emulates deletion of module_b + File projectWithModuleA = new XooProjectBuilder(PROJECT_KEY) + .addModules("module_a") + .build(temp.newFolder()); + analyze(organization, projectWithModuleA); + assertThat(countFilesInProject()).isEqualTo(2); + + // update the project key + updateProjectKey(PROJECT_KEY, "renamed", false); + assertThat(tester.projects().exists(PROJECT_KEY)).isFalse(); + + // analysis of new project, re-enabling the deleted module + File projectWithModulesBC = new XooProjectBuilder(PROJECT_KEY) + .addModules("module_b", "module_c") + .build(temp.newFolder()); + analyze(organization, projectWithModulesBC); + assertThat(countFilesInProject()).isEqualTo(3); + } + + @Test + public void simulate_update_key_of_modules() throws Exception { + Organizations.Organization organization = tester.organizations().generate(); + + File project = new XooProjectBuilder(PROJECT_KEY) + .addModules("module_a", "module_b") + .build(temp.newFolder()); + analyze(organization, project); + assertThat(tester.projects().exists(PROJECT_KEY)).isTrue(); + + // simulate update of project key + Projects.BulkUpdateKeyWsResponse response = updateProjectKey(PROJECT_KEY, "renamed", true); + + assertThat(tester.projects().exists(PROJECT_KEY)).isTrue(); + assertThat(tester.projects().exists("renamed")).isFalse(); + assertThat(response.getKeysList()) + .extracting(Key::getKey, Key::getNewKey) + .containsExactlyInAnyOrder( + tuple(PROJECT_KEY, "renamed"), + tuple(PROJECT_KEY + ":module_a", "renamed:module_a"), + tuple(PROJECT_KEY + ":module_b", "renamed:module_b")); + } + + @Test + public void simulate_update_key_of_disabled_modules() throws Exception { + Organizations.Organization organization = tester.organizations().generate(); + + // first analysis + File projectWithModulesAB = new XooProjectBuilder(PROJECT_KEY) + .addModules("module_a", "module_b") + .build(temp.newFolder()); + analyze(organization, projectWithModulesAB); + assertThat(countFilesInProject()).isEqualTo(3); + + // second analysis emulates deletion of module_b + File projectWithModuleA = new XooProjectBuilder(PROJECT_KEY) + .addModules("module_a") + .build(temp.newFolder()); + analyze(organization, projectWithModuleA); + assertThat(countFilesInProject()).isEqualTo(2); + + // update the project key + Projects.BulkUpdateKeyWsResponse response = updateProjectKey(PROJECT_KEY, "renamed", true); + + assertThat(tester.projects().exists(PROJECT_KEY)).isTrue(); + assertThat(tester.projects().exists("renamed")).isFalse(); + assertThat(response.getKeysList()) + .extracting(Key::getKey, Key::getNewKey) + .containsExactlyInAnyOrder( + tuple(PROJECT_KEY, "renamed"), + tuple(PROJECT_KEY + ":module_a", "renamed:module_a")); + } + + private int countFilesInProject() { + TreeRequest request = new TreeRequest().setComponent(PROJECT_KEY).setQualifiers(asList("FIL")); + return tester.wsClient().components().tree(request).getComponentsCount(); + } + + private void analyze(Organizations.Organization organization, File projectDir) { + orchestrator.executeBuild(SonarScanner.create(projectDir, + "sonar.organization", organization.getKey(), + "sonar.login", "admin", "sonar.password", "admin")); } private void lockWritesOnProjectIndices() throws Exception { @@ -206,17 +346,20 @@ public class ProjectKeyUpdateTest { tester.elasticsearch().unlockWrites("projectmeasures"); } - private void updateKey(Projects.CreateWsResponse.Project project, String newKey) { - tester.wsClient().projects().updateKey(new UpdateKeyRequest().setFrom(project.getKey()).setTo(newKey)); + private void updateModuleKey(String initialKey, String newKey) { + tester.wsClient().projects().updateKey(new UpdateKeyRequest().setFrom(initialKey).setTo(newKey)); } - private void updateKey(String initialKey, String newKey) { - tester.wsClient().projects().updateKey(new UpdateKeyRequest().setFrom(initialKey).setTo(newKey)); + private Projects.BulkUpdateKeyWsResponse updateProjectKey(String initialKey, String newKey, boolean dryRun) { + return tester.wsClient().projects().bulkUpdateKey(new BulkUpdateKeyRequest() + .setProject(initialKey) + .setFrom(initialKey) + .setTo(newKey) + .setDryRun(String.valueOf(dryRun))); } private Projects.CreateWsResponse.Project createProject(Organizations.Organization organization, String key, String name) { - CreateRequest createRequest = new CreateRequest().setProject(key).setName(name).setOrganization(organization.getKey()); - return tester.wsClient().projects().create(createRequest).getProject(); + return tester.projects().provision(organization, r -> r.setProject(key).setName(name)); } private boolean isProjectInDatabase(String projectKey) { @@ -255,8 +398,58 @@ public class ProjectKeyUpdateTest { .collect(Collectors.toList()); } - private void analyzeXooSample() { - SonarScanner build = SonarScanner.create(projectDir("shared/xoo-sample")); - orchestrator.executeBuild(build); + private static class XooProjectBuilder { + private final String key; + private final List moduleKeys = new ArrayList<>(); + private int filesPerModule = 1; + + XooProjectBuilder(String projectKey) { + this.key = projectKey; + } + + XooProjectBuilder addModules(String key, String... otherKeys) { + this.moduleKeys.add(key); + this.moduleKeys.addAll(asList(otherKeys)); + return this; + } + + XooProjectBuilder setFilesPerModule(int i) { + this.filesPerModule = i; + return this; + } + + File build(File dir) { + for (String moduleKey : moduleKeys) { + generateModule(moduleKey, new File(dir, moduleKey), new Properties()); + } + Properties additionalProps = new Properties(); + additionalProps.setProperty("sonar.modules", StringUtils.join(moduleKeys, ",")); + generateModule(key, dir, additionalProps); + return dir; + } + + private void generateModule(String key, File dir, Properties additionalProps) { + try { + File sourceDir = new File(dir, "src"); + FileUtils.forceMkdir(sourceDir); + for (int i = 0; i < filesPerModule; i++) { + File sourceFile = new File(sourceDir, "File" + i + ".xoo"); + FileUtils.write(sourceFile, "content of " + sourceFile.getName()); + } + Properties props = new Properties(); + props.setProperty("sonar.projectKey", key); + props.setProperty("sonar.projectName", key); + props.setProperty("sonar.projectVersion", "1.0"); + props.setProperty("sonar.sources", sourceDir.getName()); + props.putAll(additionalProps); + File propsFile = new File(dir, "sonar-project.properties"); + try (OutputStream output = FileUtils.openOutputStream(propsFile)) { + props.store(output, "generated"); + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + } } + }