Преглед на файлове

SONAR-3718 Allow creation of components with branch with provisioning

tags/5.0
Julien Lancelot преди 9 години
родител
ревизия
dbddd10fdd

+ 86
- 5
server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java Целия файл

@@ -21,16 +21,27 @@
package org.sonar.server.component;

import org.sonar.api.ServerComponent;
import org.sonar.api.i18n.I18n;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.internal.Uuids;
import org.sonar.api.web.UserRole;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.component.ComponentKeys;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.preview.PreviewCache;
import org.sonar.core.resource.ResourceIndexerDao;
import org.sonar.core.resource.ResourceKeyUpdaterDao;
import org.sonar.server.db.DbClient;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.permission.InternalPermissionService;
import org.sonar.server.user.UserSession;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.util.Date;
import java.util.Locale;
import java.util.Map;

public class ComponentService implements ServerComponent {
@@ -39,17 +50,24 @@ public class ComponentService implements ServerComponent {

private final ResourceKeyUpdaterDao resourceKeyUpdaterDao;
private final PreviewCache previewCache;
private final I18n i18n;
private final ResourceIndexerDao resourceIndexerDao;
private final InternalPermissionService permissionService;

public ComponentService(DbClient dbClient, ResourceKeyUpdaterDao resourceKeyUpdaterDao, PreviewCache previewCache) {
public ComponentService(DbClient dbClient, ResourceKeyUpdaterDao resourceKeyUpdaterDao, PreviewCache previewCache, I18n i18n, ResourceIndexerDao resourceIndexerDao,
InternalPermissionService permissionService) {
this.dbClient = dbClient;
this.resourceKeyUpdaterDao = resourceKeyUpdaterDao;
this.previewCache = previewCache;
this.i18n = i18n;
this.resourceIndexerDao = resourceIndexerDao;
this.permissionService = permissionService;
}

public ComponentDto getByKey(String key) {
DbSession session = dbClient.openSession(false);
try {
return dbClient.componentDao().getByKey(session, key);
return getByKey(session, key);
} finally {
session.close();
}
@@ -59,7 +77,7 @@ public class ComponentService implements ServerComponent {
public ComponentDto getNullableByKey(String key) {
DbSession session = dbClient.openSession(false);
try {
return dbClient.componentDao().getNullableByKey(session, key);
return getNullableByKey(session, key);
} finally {
session.close();
}
@@ -89,7 +107,7 @@ public class ComponentService implements ServerComponent {

DbSession session = dbClient.openSession(false);
try {
ComponentDto projectOrModule = getByKey(projectOrModuleKey);
ComponentDto projectOrModule = getByKey(session, projectOrModuleKey);
resourceKeyUpdaterDao.updateKey(projectOrModule.getId(), newKey);
session.commit();

@@ -117,7 +135,7 @@ public class ComponentService implements ServerComponent {

DbSession session = dbClient.openSession(false);
try {
ComponentDto project = getByKey(projectKey);
ComponentDto project = getByKey(session, projectKey);

resourceKeyUpdaterDao.bulkUpdateKey(project.getId(), stringToReplace, replacementString);
session.commit();
@@ -131,4 +149,67 @@ public class ComponentService implements ServerComponent {
}
}

public String create(NewComponent newComponent) {
UserSession.get().checkGlobalPermission(GlobalPermissions.PROVISIONING);

DbSession session = dbClient.openSession(false);
try {
checkKeyFormat(newComponent.qualifier(), newComponent.key());
checkBranchFormat(newComponent.qualifier(), newComponent.branch());
String keyWithBranch = ComponentKeys.createKey(newComponent.key(), newComponent.branch());

ComponentDto existingComponent = getNullableByKey(keyWithBranch);
if (existingComponent != null) {
throw new BadRequestException(formatMessage("Could not create %s, key already exists: %s", newComponent.qualifier(), keyWithBranch));
}

String uuid = Uuids.create();
ComponentDto component = dbClient.componentDao().insert(session,
new ComponentDto()
.setUuid(uuid)
.setProjectUuid(uuid)
.setKey(keyWithBranch)
.setDeprecatedKey(keyWithBranch)
.setName(newComponent.name())
.setLongName(newComponent.name())
.setScope(Scopes.PROJECT)
.setQualifier(newComponent.qualifier())
.setCreatedAt(new Date()));
resourceIndexerDao.indexResource(session, component.getId());
session.commit();

permissionService.applyDefaultPermissionTemplate(component.key());
return component.key();
} finally {
session.close();
}
}

private void checkKeyFormat(String qualifier, String kee) {
if (!ComponentKeys.isValidModuleKey(kee)) {
throw new BadRequestException(formatMessage("Malformed key for %s: %s. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.",
qualifier, kee));
}
}

private void checkBranchFormat(String qualifier, @Nullable String branch) {
if (branch != null && !ComponentKeys.isValidBranch(branch)) {
throw new BadRequestException(formatMessage("Malformed branch for %s: %s. Allowed characters are alphanumeric, '-', '_', '.' and '/', with at least one non-digit.",
qualifier, branch));
}
}

private String formatMessage(String message, String qualifier, String key) {
return String.format(message, i18n.message(Locale.getDefault(), "qualifier." + qualifier, "Project"), key);
}

@CheckForNull
private ComponentDto getNullableByKey(DbSession session, String key) {
return dbClient.componentDao().getNullableByKey(session, key);
}

private ComponentDto getByKey(DbSession session, String key) {
return dbClient.componentDao().getByKey(session, key);
}

}

+ 16
- 51
server/sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java Целия файл

@@ -24,33 +24,28 @@ import org.sonar.api.component.Component;
import org.sonar.api.component.RubyComponentService;
import org.sonar.api.i18n.I18n;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.internal.Uuids;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.component.ComponentKeys;
import org.sonar.core.resource.ResourceDao;
import org.sonar.core.resource.ResourceDto;
import org.sonar.core.resource.ResourceIndexerDao;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.util.RubyUtils;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.util.*;
import java.util.List;
import java.util.Map;

public class DefaultRubyComponentService implements RubyComponentService {

private final ResourceDao resourceDao;
private final DefaultComponentFinder finder;
private final ResourceIndexerDao resourceIndexerDao;
private final ComponentService componentService;
private final I18n i18n;

public DefaultRubyComponentService(ResourceDao resourceDao, DefaultComponentFinder finder, ResourceIndexerDao resourceIndexerDao, ComponentService componentService, I18n i18n) {
public DefaultRubyComponentService(ResourceDao resourceDao, DefaultComponentFinder finder, ComponentService componentService, I18n i18n) {
this.resourceDao = resourceDao;
this.finder = finder;
this.resourceIndexerDao = resourceIndexerDao;
this.componentService = componentService;
this.i18n = i18n;
}
@@ -66,48 +61,28 @@ public class DefaultRubyComponentService implements RubyComponentService {
return componentService.getNullableByUuid(uuid);
}

/**
* Be careful when updating this method, it's used by the Views plugin
*/
@CheckForNull
public Long createComponent(String kee, String name, String qualifier) {
public Long createComponent(String key, String name, String qualifier) {
return createComponent(key, null, name, qualifier);
}

@CheckForNull
public Long createComponent(String key, @Nullable String branch, String name, @Nullable String qualifier) {
// Sub view should not be created with provisioning. Will be fixed by http://jira.sonarsource.com/browse/VIEWS-296
if (!Qualifiers.SUBVIEW.equals(qualifier)) {
ComponentDto component = (ComponentDto) resourceDao.findByKey(kee);
if (component != null) {
throw new BadRequestException(formatMessage("Could not create %s, key already exists: %s", qualifier, kee));
}
checkKeyFormat(qualifier, kee);

String uuid = Uuids.create();
resourceDao.insertOrUpdate(
new ResourceDto()
.setUuid(uuid)
.setProjectUuid(uuid)
.setKey(kee)
.setDeprecatedKey(kee)
.setName(name)
.setLongName(name)
.setScope(Scopes.PROJECT)
.setQualifier(qualifier)
.setCreatedAt(new Date()));
component = (ComponentDto) resourceDao.findByKey(kee);
String createdKey = componentService.create(NewComponent.create(key, name).setQualifier(qualifier).setBranch(branch));
ComponentDto component = (ComponentDto) resourceDao.findByKey(createdKey);
if (component == null) {
throw new BadRequestException(String.format("Component not created: %s", kee));
throw new BadRequestException(String.format("Component not created: %s", createdKey));
}
resourceIndexerDao.indexResource(component.getId());
return component.getId();
}
return null;
}

public void updateComponent(Long id, String key, String name) {
ResourceDto resource = resourceDao.getResource(id);
if (resource == null) {
throw new NotFoundException();
}
checkKeyFormat(resource.getQualifier(), key);

resourceDao.insertOrUpdate(resource.setKey(key).setName(name));
}

public DefaultComponentQueryResult find(Map<String, Object> params) {
ComponentQuery query = toQuery(params);
List<Component> components = resourceDao.selectProjectsByQualifiers(query.qualifiers());
@@ -158,14 +133,4 @@ public class DefaultRubyComponentService implements RubyComponentService {
return builder.build();
}

private void checkKeyFormat(String qualifier, String kee) {
if (!ComponentKeys.isValidModuleKey(kee)) {
throw new BadRequestException(formatMessage("Malformed key for %s: %s. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.",
qualifier, kee));
}
}

private String formatMessage(String message, String qualifier, String key) {
return String.format(message, i18n.message(Locale.getDefault(), "qualifier." + qualifier, "Project"), key);
}
}

+ 73
- 0
server/sonar-server/src/main/java/org/sonar/server/component/NewComponent.java Целия файл

@@ -0,0 +1,73 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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.component;

import com.google.common.base.Preconditions;
import org.sonar.api.resources.Qualifiers;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

public class NewComponent {

private String key;
private String branch;
private String qualifier;
private String name;

public NewComponent(String key, String name) {
this.key = key;
this.name = name;
}

public String key() {
return key;
}

public String name() {
return name;
}

@CheckForNull
public String branch() {
return branch;
}

public NewComponent setBranch(@Nullable String branch) {
this.branch = branch;
return this;
}

public String qualifier() {
return qualifier != null ? qualifier : Qualifiers.PROJECT;
}

public NewComponent setQualifier(@Nullable String qualifier) {
this.qualifier = qualifier;
return this;
}

public static NewComponent create(String key, String name) {
Preconditions.checkNotNull(key, "Key can't be null");
Preconditions.checkNotNull(name, "Name can't be null");
return new NewComponent(key, name);
}
}

+ 127
- 18
server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceMediumTest.java Целия файл

@@ -24,25 +24,26 @@ import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.security.DefaultGroups;
import org.sonar.api.web.UserRole;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.rule.RuleDto;
import org.sonar.server.component.db.ComponentDao;
import org.sonar.server.db.DbClient;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.permission.InternalPermissionService;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.rule.RuleTesting;
import org.sonar.server.rule.db.RuleDao;
import org.sonar.server.platform.Platform;
import org.sonar.server.tester.ServerTester;
import org.sonar.server.user.MockUserSession;

import java.util.Map;

import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;

public class ComponentServiceMediumTest {

@@ -52,8 +53,6 @@ public class ComponentServiceMediumTest {
DbClient db;
DbSession session;
ComponentService service;
ComponentDto project;
RuleDto rule;

@Before
public void setUp() throws Exception {
@@ -61,19 +60,6 @@ public class ComponentServiceMediumTest {
db = tester.get(DbClient.class);
session = db.openSession(false);
service = tester.get(ComponentService.class);

project = ComponentTesting.newProjectDto().setKey("sample:root");
tester.get(ComponentDao.class).insert(session, project);
session.commit();

// project can be seen by anyone
MockUserSession.set().setLogin("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
tester.get(InternalPermissionService.class).addPermission(new PermissionChange().setComponentKey(project.getKey()).setGroup(DefaultGroups.ANYONE).setPermission(UserRole.USER));

rule = RuleTesting.newXooX1();
tester.get(RuleDao.class).insert(session, rule);

session.commit();
}

@After
@@ -83,28 +69,33 @@ public class ComponentServiceMediumTest {

@Test
public void get_by_key() throws Exception {
ComponentDto project = createProject("sample:root");
assertThat(service.getByKey(project.getKey())).isNotNull();
}

@Test
public void get_nullable_by_key() throws Exception {
ComponentDto project = createProject("sample:root");
assertThat(service.getNullableByKey(project.getKey())).isNotNull();
assertThat(service.getNullableByKey("unknown")).isNull();
}

@Test
public void get_by_uuid() throws Exception {
ComponentDto project = createProject("sample:root");
assertThat(service.getByUuid(project.uuid())).isNotNull();
}

@Test
public void get_nullable_by_uuid() throws Exception {
ComponentDto project = createProject("sample:root");
assertThat(service.getNullableByUuid(project.uuid())).isNotNull();
assertThat(service.getNullableByUuid("unknown")).isNull();
}

@Test
public void update_project_key() throws Exception {
ComponentDto project = createProject("sample:root");
ComponentDto file = ComponentTesting.newFileDto(project).setKey("sample:root:src/File.xoo");
tester.get(ComponentDao.class).insert(session, file);

@@ -128,6 +119,7 @@ public class ComponentServiceMediumTest {

@Test
public void update_module_key() throws Exception {
ComponentDto project = createProject("sample:root");
ComponentDto module = ComponentTesting.newModuleDto(project).setKey("sample:root:module");
tester.get(ComponentDao.class).insert(session, module);

@@ -176,12 +168,14 @@ public class ComponentServiceMediumTest {

@Test(expected = ForbiddenException.class)
public void fail_to_update_project_key_without_admin_permission() throws Exception {
ComponentDto project = createProject("sample:root");
MockUserSession.set().setLogin("john").addComponentPermission(UserRole.USER, project.key(), project.key());
service.updateKey(project.key(), "sample2:root");
}

@Test
public void check_module_keys_before_renaming() throws Exception {
ComponentDto project = createProject("sample:root");
ComponentDto module = ComponentTesting.newModuleDto(project).setKey("sample:root:module");
tester.get(ComponentDao.class).insert(session, module);

@@ -200,6 +194,7 @@ public class ComponentServiceMediumTest {

@Test
public void check_module_keys_before_renaming_return_duplicate_key() throws Exception {
ComponentDto project = createProject("sample:root");
ComponentDto module = ComponentTesting.newModuleDto(project).setKey("sample:root:module");
tester.get(ComponentDao.class).insert(session, module);

@@ -218,12 +213,14 @@ public class ComponentServiceMediumTest {

@Test(expected = ForbiddenException.class)
public void fail_to_check_module_keys_before_renaming_without_admin_permission() throws Exception {
ComponentDto project = createProject("sample:root");
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 project = createProject("sample:root");
ComponentDto module = ComponentTesting.newModuleDto(project).setKey("sample:root:module");
tester.get(ComponentDao.class).insert(session, module);

@@ -273,8 +270,120 @@ public class ComponentServiceMediumTest {

@Test(expected = ForbiddenException.class)
public void fail_to_bulk_update_project_key_without_admin_permission() throws Exception {
ComponentDto project = createProject("sample:root");
MockUserSession.set().setLogin("john").addProjectPermissions(UserRole.USER, project.key());
service.bulkUpdateKey("sample:root", "sample", "sample2");
}

@Test
public void create_project() throws Exception {
executeStartupTasksToCreateDefaultPermissionTemplate();
MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.PROVISIONING);

String key = service.create(NewComponent.create("struts", "Struts project"));

ComponentDto project = service.getNullableByKey(key);
assertThat(project.key()).isEqualTo("struts");
assertThat(project.deprecatedKey()).isEqualTo("struts");
assertThat(project.uuid()).isNotNull();
assertThat(project.projectUuid()).isEqualTo(project.uuid());
assertThat(project.moduleUuid()).isNull();
assertThat(project.moduleUuidPath()).isNull();
assertThat(project.name()).isEqualTo("Struts project");
assertThat(project.longName()).isEqualTo("Struts project");
assertThat(project.scope()).isEqualTo("PRJ");
assertThat(project.qualifier()).isEqualTo("TRK");
assertThat(project.getCreatedAt()).isNotNull();
}

@Test
public void create_new_project_with_branch() throws Exception {
executeStartupTasksToCreateDefaultPermissionTemplate();
MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.PROVISIONING);

String key = service.create(NewComponent.create("struts", "Struts project").setBranch("origin/branch"));

ComponentDto project = service.getNullableByKey(key);
assertThat(project.key()).isEqualTo("struts:origin/branch");
assertThat(project.deprecatedKey()).isEqualTo("struts:origin/branch");
}

@Test
public void create_view() throws Exception {
executeStartupTasksToCreateDefaultPermissionTemplate();
MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.PROVISIONING);

String key = service.create(NewComponent.create("all-project", "All Projects").setQualifier(Qualifiers.VIEW));

ComponentDto project = service.getNullableByKey(key);
assertThat(project.key()).isEqualTo("all-project");
assertThat(project.deprecatedKey()).isEqualTo("all-project");
assertThat(project.uuid()).isNotNull();
assertThat(project.projectUuid()).isEqualTo(project.uuid());
assertThat(project.moduleUuid()).isNull();
assertThat(project.moduleUuidPath()).isNull();
assertThat(project.name()).isEqualTo("All Projects");
assertThat(project.longName()).isEqualTo("All Projects");
assertThat(project.scope()).isEqualTo("PRJ");
assertThat(project.qualifier()).isEqualTo("VW");
assertThat(project.getCreatedAt()).isNotNull();
}

@Test
public void fail_to_create_new_component_on_invalid_key() throws Exception {
MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.PROVISIONING);

try {
service.create(NewComponent.create("struts?parent", "Struts project"));
fail();
} catch (Exception e){
assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("Malformed key for Project: struts?parent. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.");
}
}

@Test
public void fail_to_create_new_component_on_invalid_branch() throws Exception {
MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.PROVISIONING);

try {
service.create(NewComponent.create("struts", "Struts project").setBranch("origin?branch"));
fail();
} catch (Exception e){
assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("Malformed branch for Project: origin?branch. Allowed characters are alphanumeric, '-', '_', '.' and '/', with at least one non-digit.");
}
}

@Test
public void fail_to_create_new_component_if_key_already_exists() throws Exception {
MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.PROVISIONING);

ComponentDto project = ComponentTesting.newProjectDto().setKey("struts");
tester.get(ComponentDao.class).insert(session, project);
session.commit();

try {
service.create(NewComponent.create("struts", "Struts project"));
fail();
} catch (Exception e){
assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("Could not create Project, key already exists: struts");
}
}

private ComponentDto createProject(String key){
ComponentDto project = ComponentTesting.newProjectDto().setKey("sample:root");
tester.get(ComponentDao.class).insert(session, project);
session.commit();

// project can be seen by anyone
MockUserSession.set().setLogin("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
tester.get(InternalPermissionService.class).addPermission(new PermissionChange().setComponentKey(project.getKey()).setGroup(DefaultGroups.ANYONE).setPermission(UserRole.USER));
MockUserSession.set();

return project;
}

private void executeStartupTasksToCreateDefaultPermissionTemplate(){
tester.get(Platform.class).executeStartupTasks();
}

}

+ 15
- 77
server/sonar-server/src/test/java/org/sonar/server/component/DefaultRubyComponentServiceTest.java Целия файл

@@ -26,13 +26,9 @@ import org.mockito.ArgumentCaptor;
import org.sonar.api.component.Component;
import org.sonar.api.i18n.I18n;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.resource.ResourceDao;
import org.sonar.core.resource.ResourceDto;
import org.sonar.core.resource.ResourceIndexerDao;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;

import java.util.List;
import java.util.Map;
@@ -48,7 +44,6 @@ public class DefaultRubyComponentServiceTest {

ResourceDao resourceDao;
DefaultComponentFinder finder;
ResourceIndexerDao resourceIndexerDao;
ComponentService componentService;
I18n i18n;

@@ -58,10 +53,9 @@ public class DefaultRubyComponentServiceTest {
public void before() {
resourceDao = mock(ResourceDao.class);
finder = mock(DefaultComponentFinder.class);
resourceIndexerDao = mock(ResourceIndexerDao.class);
componentService = mock(ComponentService.class);
i18n = mock(I18n.class);
service = new DefaultRubyComponentService(resourceDao, finder, resourceIndexerDao, componentService, i18n);
service = new DefaultRubyComponentService(resourceDao, finder, componentService, i18n);
}

@Test
@@ -81,49 +75,35 @@ public class DefaultRubyComponentServiceTest {
}

@Test
public void create_component_and_index_it() {
public void create_component() {
String componentKey = "new-project";
String componentName = "New Project";
String qualifier = Qualifiers.PROJECT;
long componentId = Long.MAX_VALUE;
ComponentDto component = mock(ComponentDto.class);
when(component.getId()).thenReturn(componentId);
when(resourceDao.findByKey(componentKey)).thenReturn(null).thenReturn(component);
when(resourceDao.findByKey(componentKey)).thenReturn(ComponentTesting.newProjectDto());
when(componentService.create(any(NewComponent.class))).thenReturn(componentKey);

service.createComponent(componentKey, componentName, qualifier);

ArgumentCaptor<ResourceDto> resourceCaptor = ArgumentCaptor.forClass(ResourceDto.class);
verify(resourceDao).insertOrUpdate(resourceCaptor.capture());
ResourceDto created = resourceCaptor.getValue();
assertThat(created.getUuid()).isNotNull();
assertThat(created.getProjectUuid()).isEqualTo(created.getUuid());
assertThat(created.getKey()).isEqualTo(componentKey);
assertThat(created.getName()).isEqualTo(componentName);
assertThat(created.getLongName()).isEqualTo(componentName);
assertThat(created.getScope()).isEqualTo(Scopes.PROJECT);
assertThat(created.getQualifier()).isEqualTo(qualifier);
verify(resourceDao, times(2)).findByKey(componentKey);
verify(resourceIndexerDao).indexResource(componentId);
ArgumentCaptor<NewComponent> newComponentArgumentCaptor = ArgumentCaptor.forClass(NewComponent.class);
verify(componentService).create(newComponentArgumentCaptor.capture());
NewComponent newComponent = newComponentArgumentCaptor.getValue();
assertThat(newComponent.key()).isEqualTo(componentKey);
assertThat(newComponent.name()).isEqualTo(componentName);
assertThat(newComponent.branch()).isNull();
assertThat(newComponent.qualifier()).isEqualTo(Qualifiers.PROJECT);
}

@Test
public void not_create_component_on_sub_views() {
String componentKey = "new-project";
String componentName = "New Project";
String qualifier = Qualifiers.SUBVIEW;
long componentId = Long.MAX_VALUE;
ComponentDto component = mock(ComponentDto.class);
when(component.getId()).thenReturn(componentId);
when(resourceDao.findByKey(componentKey)).thenReturn(null).thenReturn(component);
when(resourceDao.findByKey(anyString())).thenReturn(ComponentTesting.newProjectDto());

service.createComponent(componentKey, componentName, qualifier);
service.createComponent("new-project", "New Project", Qualifiers.SUBVIEW);

verify(resourceDao, never()).insertOrUpdate(any(ResourceDto.class));
verifyZeroInteractions(resourceIndexerDao);
verify(componentService, never()).create(any(NewComponent.class));
}

@Test(expected = BadRequestException.class)
public void should_thow_if_create_fails() {
public void should_throw_exception_if_create_fails() {
String componentKey = "new-project";
String componentName = "New Project";
String qualifier = Qualifiers.PROJECT;
@@ -132,53 +112,11 @@ public class DefaultRubyComponentServiceTest {
service.createComponent(componentKey, componentName, qualifier);
}

@Test(expected = BadRequestException.class)
public void should_throw_if_component_already_exists() {
String componentKey = "new-project";
String componentName = "New Project";
String qualifier = Qualifiers.PROJECT;
when(resourceDao.findByKey(componentKey)).thenReturn(mock(ComponentDto.class));

service.createComponent(componentKey, componentName, qualifier);
}

@Test(expected = BadRequestException.class)
public void should_throw_if_malformed_key1() {
service.createComponent("1234", "New Project", Qualifiers.PROJECT);
}

@Test(expected = NotFoundException.class)
public void should_throw_if_updating_unknown_component() {
final long componentId = 1234l;
when(resourceDao.getResource(componentId)).thenReturn(null);
service.updateComponent(componentId, "key", "name");
}

@Test
public void should_update_component() {
final long componentId = 1234l;
final String newKey = "newKey";
final String newName = "newName";
ResourceDto resource = mock(ResourceDto.class);
when(resourceDao.getResource(componentId)).thenReturn(resource);
when(resource.setKey(newKey)).thenReturn(resource);
when(resource.setName(newName)).thenReturn(resource);
service.updateComponent(componentId, newKey, newName);
verify(resource).setKey(newKey);
verify(resource).setName(newName);
verify(resourceDao).insertOrUpdate(resource);
}

@Test(expected=BadRequestException.class)
public void should_throw_if_malformed_key_in_update() {
final long componentId = 1234l;
final String newKey = "new/key";
final String newName = "newName";
ResourceDto resource = mock(ResourceDto.class);
when(resourceDao.getResource(componentId)).thenReturn(resource);
service.updateComponent(componentId, newKey, newName);
}

@Test
public void should_find() {
List<String> qualifiers = newArrayList("TRK");

+ 3
- 7
server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/projects_controller.rb Целия файл

@@ -71,20 +71,16 @@ class Api::ProjectsController < Api::ApiController
# POST /api/projects/create?key=<key>&name=<name>
#
# -- Example
# curl -v -u admin:admin -X POST 'http://localhost:9000/api/projects/create?key=project1&name=Project%20One'
# curl -v -u admin:admin -X POST 'http://localhost:9000/api/projects/create?key=project1&name=Project%20One&branch=origin/master'
#
# since 4.0
#
def create
verify_post_request
require_parameters :key, :name
access_denied unless has_role?("provisioning")
key = params[:key]
name = params[:name]

Internal.component_api.createComponent(key, name, 'TRK')
Internal.permissions.applyDefaultPermissionTemplate(key)
result = Project.by_key(key)
id = Internal.component_api.createComponent(params[:key], params[:branch], params[:name], nil)
result = Project.find(id.to_i)

respond_to do |format|
format.json { render :json => jsonp(to_json_hash(result)) }

+ 4
- 15
server/sonar-web/src/main/webapp/WEB-INF/app/controllers/provisioning_controller.rb Целия файл

@@ -33,34 +33,23 @@ class ProvisioningController < ApplicationController
) { |p| p.key }
end

def create_or_update
def create
verify_post_request
access_denied unless has_role?("provisioning")
@id = params[:id]
@key = params[:key]
@name = params[:name]
@branch = params[:branch]

begin
bad_request('provisioning.missing.key') if @key.blank?
bad_request('provisioning.missing.name') if @name.blank?

if @id.nil? or @id.empty?
Internal.component_api.createComponent(@key, @name, 'TRK')
begin
Internal.permissions.applyDefaultPermissionTemplate(@key)
rescue
# Programmatic transaction rollback
Java::OrgSonarServerUi::JRubyFacade.getInstance().deleteResourceTree(@key)
raise
end
else
Internal.component_api.updateComponent(@id.to_i, @key, @name)
end
Internal.component_api.createComponent(@key, @branch, @name, nil)

redirect_to :action => 'index'
rescue Exception => e
flash.now[:error]= Api::Utils.message(e.message)
render :partial => 'create_form', :id => @id, :key => @key, :name => @name, :status => 400
render :partial => 'create_form', :key => @key, :branch => @branch, :name => @name, :status => 400
end
end


+ 7
- 4
server/sonar-web/src/main/webapp/WEB-INF/app/views/provisioning/_create_form.html.erb Целия файл

@@ -1,8 +1,7 @@
<form id="create-resource-form" method="post" action="<%= ApplicationController.root_context -%>/provisioning/create_or_update">
<input type="hidden" name="id" value="<%= @id -%>"/>
<form id="create-resource-form" method="post" action="<%= ApplicationController.root_context -%>/provisioning/create">
<fieldset>
<div class="modal-head">
<h2><%= message((@id.nil? || @id.empty?) ? 'qualifiers.new.TRK' : 'qualifiers.update.TRK') -%></h2>
<h2><%= message('qualifiers.new.TRK') -%></h2>
</div>
<div class="modal-body">
<% if flash.now[:error] %>
@@ -12,13 +11,17 @@
<label for="key"><%= h message('key') -%> <em class="mandatory">*</em></label>
<input id="key" name="key" value="<%= h @key -%>" type="text" size="50" maxlength="400" autofocus="autofocus"/>
</div>
<div class="modal-field">
<label for="branch"><%= h message('branch') -%></label>
<input id="branch" name="branch" value="<%= h @branch -%>" type="text" size="50" maxlength="400" autofocus="autofocus"/>
</div>
<div class="modal-field">
<label for="name"><%= h message('name') -%> <em class="mandatory">*</em></label>
<input id="name" name="name" value="<%= h @name -%>" type="text" size="50" maxlength="256" value=""/>
</div>
</div>
<div class="modal-foot">
<input type="submit" value="<%= h message((@id.nil? || @id.empty?) ? 'qualifiers.create.TRK' : 'qualifiers.update.TRK') -%>" id="save-submit"/>
<input type="submit" value="<%= h message('qualifiers.create.TRK') -%>" id="save-submit"/>
<a href="#" onclick="return closeModalWindow()" id="save-cancel"><%= h message('cancel') -%></a>
</div>
</fieldset>

+ 0
- 3
server/sonar-web/src/main/webapp/WEB-INF/app/views/provisioning/index.html.erb Целия файл

@@ -33,9 +33,6 @@
<td><%= h resource.name -%></td>
<td><%= format_datetime(resource.created_at) -%></td>
<td class="operations">
<%= link_to message('edit'), {:action => :create_form, :id => resource.id, :key => resource.key, :name => resource.name},
{:id => "edit-#{resource.key.parameterize}", :class => 'open-modal link-action'} -%>
&nbsp;
<%= link_to message('delete'), {:action => :delete_form, :id => resource.id},
{:id => "delete-#{resource.key.parameterize}", :class => 'open-modal link-action link-red'} -%>
</td>

+ 2
- 2
sonar-core/src/main/java/org/sonar/core/component/ComponentKeys.java Целия файл

@@ -105,8 +105,8 @@ public final class ComponentKeys {
* </ul>
* </li>
* </ul>
* @param keyCandidate
* @return <code>true</code> if <code>keyCandidate</code> can be used for a project/module
* @param branchCandidate
* @return <code>true</code> if <code>branchCandidate</code> can be used for a project/module
*/
public static boolean isValidBranch(String branchCandidate) {
return branchCandidate.matches(VALID_BRANCH_REGEXP);

+ 16
- 12
sonar-core/src/main/java/org/sonar/core/resource/ResourceIndexerDao.java Целия файл

@@ -132,24 +132,28 @@ public class ResourceIndexerDao {
}

public boolean indexResource(long id) {
boolean indexed = false;
SqlSession session = mybatis.openSession(false);
DbSession session = mybatis.openSession(false);
try {
ResourceIndexerMapper mapper = session.getMapper(ResourceIndexerMapper.class);
ResourceDto resource = mapper.selectResourceToIndex(id);
if (resource != null) {
Long rootId = resource.getRootId();
if (rootId == null) {
rootId = resource.getId();
}
indexed = indexResource(resource.getId(), resource.getName(), resource.getQualifier(), rootId, session, mapper);
}
return indexed;
return indexResource(session, id);
} finally {
MyBatis.closeQuietly(session);
}
}

public boolean indexResource(DbSession session, long id) {
boolean indexed = false;
ResourceIndexerMapper mapper = session.getMapper(ResourceIndexerMapper.class);
ResourceDto resource = mapper.selectResourceToIndex(id);
if (resource != null) {
Long rootId = resource.getRootId();
if (rootId == null) {
rootId = resource.getId();
}
indexed = indexResource(resource.getId(), resource.getName(), resource.getQualifier(), rootId, session, mapper);
}
return indexed;
}

public boolean indexResource(int id, String name, String qualifier, int rootId) {
boolean indexed = false;
SqlSession session = mybatis.openSession(false);

+ 1
- 1
sonar-core/src/main/resources/org/sonar/l10n/core.properties Целия файл

@@ -25,6 +25,7 @@ backup=Backup
backup_verb=Back up
blocker=Blocker
bold=Bold
branch=Branch
build_date=Build date
build_time=Build time
calendar=Calendar
@@ -379,7 +380,6 @@ qualifiers.create.TRK=Create Project
qualifiers.create.VW=Create View
qualifiers.create.DEV=Create Developer

qualifiers.update.TRK=Update Project
qualifiers.update.VW=Update View
qualifiers.update.DEV=Update Developer


Loading…
Отказ
Запис