diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-10-02 10:25:35 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-10-02 15:28:17 +0200 |
commit | 5725b5108f1c1a507e3134080fa6ba2a31ec069d (patch) | |
tree | e1c46ffe799f0ebda808f49b3181a488d8b77aad | |
parent | dd9b60a85b5cb8e76ca29759fb93fc16219b4133 (diff) | |
download | sonarqube-5725b5108f1c1a507e3134080fa6ba2a31ec069d.tar.gz sonarqube-5725b5108f1c1a507e3134080fa6ba2a31ec069d.zip |
SONAR-5663 Fix issue when updating provisioned project key
8 files changed, 154 insertions, 50 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java index 534ae2f4689..c70e96f8541 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java @@ -23,9 +23,11 @@ package org.sonar.server.component; import com.google.common.collect.ImmutableMap; import org.sonar.api.ServerComponent; import org.sonar.api.web.UserRole; +import org.sonar.core.component.AuthorizedComponentDto; import org.sonar.core.component.ComponentDto; import org.sonar.core.persistence.DbSession; import org.sonar.core.preview.PreviewCache; +import org.sonar.core.resource.ResourceDto; import org.sonar.core.resource.ResourceKeyUpdaterDao; import org.sonar.server.db.DbClient; import org.sonar.server.permission.InternalPermissionService; @@ -34,6 +36,7 @@ import org.sonar.server.user.UserSession; import javax.annotation.CheckForNull; import java.util.Date; +import java.util.Map; public class ComponentService implements ServerComponent { @@ -50,20 +53,20 @@ public class ComponentService implements ServerComponent { this.previewCache = previewCache; } - public ComponentDto getByKey(String key) { + public AuthorizedComponentDto getByKey(String key) { DbSession session = dbClient.openSession(false); try { - return dbClient.componentDao().getByKey(session, key); + return dbClient.componentDao().getAuthorizedComponentByKey(key, session); } finally { session.close(); } } @CheckForNull - public ComponentDto getNullableByKey(String key) { + public AuthorizedComponentDto getNullableByKey(String key) { DbSession session = dbClient.openSession(false); try { - return dbClient.componentDao().getNullableByKey(session, key); + return dbClient.componentDao().getNullableAuthorizedComponentByKey(key, session); } finally { session.close(); } @@ -78,16 +81,16 @@ public class ComponentService implements ServerComponent { DbSession session = dbClient.openSession(false); try { - ComponentDto projectOrModule = getByKey(projectOrModuleKey); - ComponentDto oldRootProject = dbClient.componentDao().getRootProjectByKey(projectOrModuleKey, session); + AuthorizedComponentDto projectOrModule = getByKey(projectOrModuleKey); + ResourceDto oldRootProject = dbClient.resourceDao().getRootProjectByComponentKey(session, projectOrModuleKey); resourceKeyUpdaterDao.updateKey(projectOrModule.getId(), newKey); session.commit(); - ComponentDto newRootProject = dbClient.componentDao().getRootProjectByKey(newKey, session); - updateIssuesIndex(session, oldRootProject.key(), newRootProject.key()); + ResourceDto newRootProject = dbClient.resourceDao().getRootProjectByComponentKey(session, newKey); + updateIssuesIndex(session, oldRootProject.getKey(), newRootProject.getKey()); - previewCache.reportResourceModification(newRootProject.key()); + previewCache.reportResourceModification(newRootProject.getKey()); session.commit(); } finally { @@ -95,17 +98,28 @@ public class ComponentService implements ServerComponent { } } + public Map<String, String> checkModuleKeysBeforeRenaming(String projectKey, String stringToReplace, String replacementString) { + UserSession.get().checkProjectPermission(UserRole.ADMIN, projectKey); + DbSession session = dbClient.openSession(false); + try { + AuthorizedComponentDto project = getByKey(projectKey); + return resourceKeyUpdaterDao.checkModuleKeysBeforeRenaming(project.getId(), stringToReplace, replacementString); + } finally { + session.close(); + } + } + public void bulkUpdateKey(String projectKey, String stringToReplace, String replacementString) { UserSession.get().checkProjectPermission(UserRole.ADMIN, projectKey); DbSession session = dbClient.openSession(false); try { - ComponentDto project = getByKey(projectKey); + AuthorizedComponentDto project = getByKey(projectKey); resourceKeyUpdaterDao.bulkUpdateKey(project.getId(), stringToReplace, replacementString); session.commit(); - ComponentDto newProject = dbClient.componentDao().getById(project.getId(), session); + AuthorizedComponentDto newProject = dbClient.componentDao().getNullableAuthorizedComponentById(project.getId(), session); updateIssuesIndex(session, projectKey, newProject.key()); previewCache.reportResourceModification(newProject.key()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java b/server/sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java index de8be6e9791..62ad40944e3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java @@ -120,6 +120,10 @@ public class DefaultRubyComponentService implements RubyComponentService { componentService.updateKey(projectOrModuleKey, newKey); } + public Map<String, String> checkModuleKeysBeforeRenaming(String projectKey, String stringToReplace, String replacementString) { + return componentService.checkModuleKeysBeforeRenaming(projectKey, stringToReplace, replacementString); + } + public void bulkUpdateKey(String projectKey, String stringToReplace, String replacementString) { componentService.bulkUpdateKey(projectKey, stringToReplace, replacementString); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java b/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java index 277d7a13070..5fdc07b3fca 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java @@ -34,7 +34,6 @@ import org.sonar.api.web.*; import org.sonar.core.persistence.Database; import org.sonar.core.preview.PreviewCache; import org.sonar.core.resource.ResourceIndexerDao; -import org.sonar.core.resource.ResourceKeyUpdaterDao; import org.sonar.core.timemachine.Periods; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.db.migrations.DatabaseMigrator; @@ -363,19 +362,6 @@ public final class JRubyFacade { return Platform.getInstance().getContainer(); } - // UPDATE PROJECT KEY ------------------------------------------------------------------ - public void updateResourceKey(long projectId, String newKey) { - get(ResourceKeyUpdaterDao.class).updateKey(projectId, newKey); - } - - public Map<String, String> checkModuleKeysBeforeRenaming(long projectId, String stringToReplace, String replacementString) { - return get(ResourceKeyUpdaterDao.class).checkModuleKeysBeforeRenaming(projectId, stringToReplace, replacementString); - } - - public void bulkUpdateKey(long projectId, String stringToReplace, String replacementString) { - get(ResourceKeyUpdaterDao.class).bulkUpdateKey(projectId, stringToReplace, replacementString); - } - // USERS public void onNewUser(Map<String, String> fields) { NewUserNotifier notifier = get(NewUserNotifier.class); diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceMediumTest.java index 9415fd8e9d5..b3e602dbd55 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceMediumTest.java @@ -35,18 +35,19 @@ import org.sonar.server.component.db.ComponentDao; import org.sonar.server.component.db.SnapshotDao; import org.sonar.server.db.DbClient; import org.sonar.server.exceptions.ForbiddenException; -import org.sonar.server.issue.IssueQuery; import org.sonar.server.issue.IssueTesting; import org.sonar.server.issue.index.IssueAuthorizationIndex; import org.sonar.server.issue.index.IssueIndex; import org.sonar.server.rule.RuleTesting; import org.sonar.server.rule.db.RuleDao; import org.sonar.server.search.IndexClient; -import org.sonar.server.search.QueryContext; +import org.sonar.server.search.IndexDefinition; +import org.sonar.server.search.SearchClient; import org.sonar.server.tester.ServerTester; import org.sonar.server.user.MockUserSession; import java.util.Date; +import java.util.Map; import static org.fest.assertions.Assertions.assertThat; @@ -130,11 +131,12 @@ public class ComponentServiceMediumTest { assertThat(tester.get(IssueIndex.class).getNullableByKey(issue.getKey()).projectKey()).isEqualTo("sample2:root"); // Check that no new issue has been added - assertThat(tester.get(IssueIndex.class).search(IssueQuery.builder().build(), new QueryContext()).getTotal()).isEqualTo(1); + assertThat(tester.get(SearchClient.class).prepareCount(IndexDefinition.ISSUES.getIndexName()).setTypes(IndexDefinition.ISSUES.getIndexType()).get().getCount()).isEqualTo(1); // Check Issue Authorization index assertThat(tester.get(IssueAuthorizationIndex.class).getNullableByKey(project.getKey())).isNull(); assertThat(tester.get(IssueAuthorizationIndex.class).getNullableByKey("sample2:root")).isNotNull(); + assertThat(tester.get(SearchClient.class).prepareCount(IndexDefinition.ISSUES_AUTHORIZATION.getIndexName()).setTypes(IndexDefinition.ISSUES_AUTHORIZATION.getIndexType()).get().getCount()).isEqualTo(1); // Check dry run cache have been updated assertThat(db.propertiesDao().selectProjectProperties("sample2:root", session)).hasSize(1); @@ -181,6 +183,25 @@ public class ComponentServiceMediumTest { assertThat(db.propertiesDao().selectProjectProperties(project.key(), session)).hasSize(1); } + @Test + public void update_provisioned_project_key() throws Exception { + ComponentDto provisionedProject = ComponentTesting.newProjectDto().setKey("provisionedProject"); + tester.get(ComponentDao.class).insert(session, provisionedProject); + + session.commit(); + + MockUserSession.set().setLogin("john").addComponentPermission(UserRole.ADMIN, provisionedProject.key(), provisionedProject.key()); + service.updateKey(provisionedProject.key(), "provisionedProject2"); + session.commit(); + + // Check project key has been updated + assertThat(service.getNullableByKey(provisionedProject.key())).isNull(); + assertThat(service.getNullableByKey("provisionedProject2")).isNotNull(); + + // Check dry run cache have been updated + assertThat(db.propertiesDao().selectProjectProperties("provisionedProject2", session)).hasSize(1); + } + @Test(expected = ForbiddenException.class) public void fail_to_update_project_key_without_admin_permission() throws Exception { MockUserSession.set().setLogin("john").addComponentPermission(UserRole.USER, project.key(), project.key()); @@ -188,6 +209,52 @@ public class ComponentServiceMediumTest { } @Test + public void check_module_keys_before_renaming() throws Exception { + ComponentDto module = ComponentTesting.newModuleDto(project).setKey("sample:root:module"); + tester.get(ComponentDao.class).insert(session, module); + tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(module, project)); + + ComponentDto file = ComponentTesting.newFileDto(module).setKey("sample:root:module:src/File.xoo"); + tester.get(ComponentDao.class).insert(session, file); + tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(file, project)); + + session.commit(); + + MockUserSession.set().setLogin("john").addProjectPermissions(UserRole.ADMIN, project.key()); + Map<String, String> result = service.checkModuleKeysBeforeRenaming(project.key(), "sample", "sample2"); + + assertThat(result).hasSize(2); + assertThat(result.get("sample:root")).isEqualTo("sample2:root"); + assertThat(result.get("sample:root:module")).isEqualTo("sample2:root:module"); + } + + @Test + public void check_module_keys_before_renaming_return_duplicate_key() throws Exception { + ComponentDto module = ComponentTesting.newModuleDto(project).setKey("sample:root:module"); + tester.get(ComponentDao.class).insert(session, module); + tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(module, project)); + + ComponentDto module2 = ComponentTesting.newModuleDto(project).setKey("foo:module"); + tester.get(ComponentDao.class).insert(session, module2); + tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(module2, project)); + + session.commit(); + + MockUserSession.set().setLogin("john").addProjectPermissions(UserRole.ADMIN, project.key()); + Map<String, String> result = service.checkModuleKeysBeforeRenaming(project.key(), "sample:root", "foo"); + + assertThat(result).hasSize(2); + assertThat(result.get("sample:root")).isEqualTo("foo"); + assertThat(result.get("sample:root:module")).isEqualTo("#duplicate_key#"); + } + + @Test(expected = ForbiddenException.class) + public void fail_to_check_module_keys_before_renaming_without_admin_permission() throws Exception { + MockUserSession.set().setLogin("john").addComponentPermission(UserRole.USER, project.key(), project.key()); + service.checkModuleKeysBeforeRenaming(project.key(), "sample", "sample2"); + } + + @Test public void bulk_update_project_key() throws Exception { ComponentDto module = ComponentTesting.newModuleDto(project).setKey("sample:root:module"); tester.get(ComponentDao.class).insert(session, module); @@ -203,7 +270,7 @@ public class ComponentServiceMediumTest { session.commit(); MockUserSession.set().setLogin("john").addProjectPermissions(UserRole.ADMIN, project.key()); - service.bulkUpdateKey("sample:root", "sample", "sample2"); + service.bulkUpdateKey(project.key(), "sample", "sample2"); session.commit(); // Check project key has been updated @@ -223,16 +290,36 @@ public class ComponentServiceMediumTest { assertThat(tester.get(IssueIndex.class).getNullableByKey(issue.getKey()).projectKey()).isEqualTo("sample2:root"); // Check that no new issue has been added - assertThat(tester.get(IssueIndex.class).search(IssueQuery.builder().build(), new QueryContext()).getTotal()).isEqualTo(1); + assertThat(tester.get(SearchClient.class).prepareCount(IndexDefinition.ISSUES.getIndexName()).setTypes(IndexDefinition.ISSUES.getIndexType()).get().getCount()).isEqualTo(1); // Check Issue Authorization index assertThat(tester.get(IssueAuthorizationIndex.class).getNullableByKey(project.getKey())).isNull(); assertThat(tester.get(IssueAuthorizationIndex.class).getNullableByKey("sample2:root")).isNotNull(); + assertThat(tester.get(SearchClient.class).prepareCount(IndexDefinition.ISSUES_AUTHORIZATION.getIndexName()).setTypes(IndexDefinition.ISSUES_AUTHORIZATION.getIndexType()).get().getCount()).isEqualTo(1); // Check dry run cache have been updated assertThat(db.propertiesDao().selectProjectProperties("sample2:root", session)).hasSize(1); } + @Test + public void bulk_update_provisioned_project_key() throws Exception { + ComponentDto provisionedProject = ComponentTesting.newProjectDto().setKey("provisionedProject"); + tester.get(ComponentDao.class).insert(session, provisionedProject); + + session.commit(); + + MockUserSession.set().setLogin("john").addComponentPermission(UserRole.ADMIN, provisionedProject.key(), provisionedProject.key()); + service.bulkUpdateKey(provisionedProject.key(), "provisionedProject", "provisionedProject2"); + session.commit(); + + // Check project key has been updated + assertThat(service.getNullableByKey(provisionedProject.key())).isNull(); + assertThat(service.getNullableByKey("provisionedProject2")).isNotNull(); + + // Check dry run cache have been updated + assertThat(db.propertiesDao().selectProjectProperties("provisionedProject2", session)).hasSize(1); + } + @Test(expected = ForbiddenException.class) public void fail_to_bulk_update_project_key_without_admin_permission() throws Exception { MockUserSession.set().setLogin("john").addProjectPermissions(UserRole.USER, project.key()); diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/DefaultRubyComponentServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/DefaultRubyComponentServiceTest.java index 28e52b6217a..8860c8c501c 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/DefaultRubyComponentServiceTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/DefaultRubyComponentServiceTest.java @@ -263,6 +263,12 @@ public class DefaultRubyComponentServiceTest { } @Test + public void check_module_keys_before_renaming() { + service.checkModuleKeysBeforeRenaming("oldKey", "old", "new"); + verify(componentService).checkModuleKeysBeforeRenaming("oldKey", "old", "new"); + } + + @Test public void bulk_update_key() { service.bulkUpdateKey("oldKey", "old", "new"); verify(componentService).bulkUpdateKey("oldKey", "old", "new"); diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_controller.rb index 09148fc3bec..8af012accdd 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_controller.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_controller.rb @@ -182,17 +182,19 @@ class ProjectController < ApplicationController flash[:error] = message('update_key.fieds_cant_be_blank_for_bulk_update') redirect_to :action => 'key', :id => @project.id else - @key_check_results = java_facade.checkModuleKeysBeforeRenaming(@project.id, @string_to_replace, @replacement_string) - @can_update = false - @duplicate_key_found = false - @key_check_results.each do |key, value| - if value=="#duplicate_key#" - @duplicate_key_found = true - else - @can_update = true + call_backend do + @key_check_results = Internal.component_api.checkModuleKeysBeforeRenaming(@project.key, @string_to_replace, @replacement_string) + @can_update = false + @duplicate_key_found = false + @key_check_results.each do |key, value| + if value=="#duplicate_key#" + @duplicate_key_found = true + else + @can_update = true + end end + @can_update = false if @duplicate_key_found end - @can_update = false if @duplicate_key_found end end diff --git a/sonar-core/src/main/java/org/sonar/core/component/AuthorizedComponentDto.java b/sonar-core/src/main/java/org/sonar/core/component/AuthorizedComponentDto.java index 7be4c1deed9..ee13722ce7c 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/AuthorizedComponentDto.java +++ b/sonar-core/src/main/java/org/sonar/core/component/AuthorizedComponentDto.java @@ -26,7 +26,7 @@ import org.sonar.core.persistence.Dto; * Used to check that a project exists. Can return provisionned projects and projects from analysis. * The root project id is not available because no join on snapshot is done to retrieve it. * - * Warning, this component should not be retrieve from db using a join on snapshots, otherwise provisionned projects will not be returned anymore. + * Warning, this component should not be retrieve from db using a join on snapshots, otherwise provisioned projects will not be returned anymore. */ public class AuthorizedComponentDto extends Dto<String> { diff --git a/sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java b/sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java index 41ae718bf99..c47cf8b997c 100644 --- a/sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java +++ b/sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java @@ -220,19 +220,24 @@ public class ResourceDao implements DaoComponent { * The implementation should rather use a new column already containing the root project, see https://jira.codehaus.org/browse/SONAR-5188. */ @CheckForNull + public ResourceDto getRootProjectByComponentKey(DbSession session, String componentKey) { + ResourceDto component = getResource(ResourceQuery.create().setKey(componentKey), session); + if (component != null) { + Long rootId = component.getRootId(); + if (rootId != null) { + return getParentModuleByComponentId(rootId, session); + } else { + return component; + } + } + return null; + } + + @CheckForNull public ResourceDto getRootProjectByComponentKey(String componentKey) { DbSession session = mybatis.openSession(false); try { - ResourceDto component = getResource(ResourceQuery.create().setKey(componentKey), session); - if (component != null) { - Long rootId = component.getRootId(); - if (rootId != null) { - return getParentModuleByComponentId(rootId, session); - } else { - return component; - } - } - return null; + return getRootProjectByComponentKey(session, componentKey); } finally { MyBatis.closeQuietly(session); } |