@@ -27,19 +27,19 @@ import org.junit.ClassRule; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.wsclient.SonarClient; | |||
import org.sonar.wsclient.base.HttpException; | |||
import org.sonar.wsclient.project.NewProject; | |||
import org.sonar.wsclient.project.Project; | |||
import org.sonarqube.ws.WsProjects.CreateWsResponse.Project; | |||
import org.sonarqube.ws.client.HttpException; | |||
import org.sonarqube.ws.client.permission.AddGroupWsRequest; | |||
import org.sonarqube.ws.client.permission.AddUserWsRequest; | |||
import org.sonarqube.ws.client.permission.PermissionsService; | |||
import org.sonarqube.ws.client.permission.RemoveGroupWsRequest; | |||
import org.sonarqube.ws.client.permission.RemoveUserWsRequest; | |||
import org.sonarqube.ws.client.project.CreateRequest; | |||
import util.user.UserRule; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static util.ItUtils.newAdminWsClient; | |||
import static util.ItUtils.newUserWsClient; | |||
import static util.selenium.Selenese.runSelenese; | |||
public class ProvisioningPermissionTest { | |||
@@ -117,13 +117,13 @@ public class ProvisioningPermissionTest { | |||
final String newKey = "new-project"; | |||
final String newName = "New Project"; | |||
SonarClient client = orchestrator.getServer().wsClient(USER_WITH_PROVISIONING, PASSWORD); | |||
Project created = client.projectClient().create(NewProject.create().key(newKey).name(newName)); | |||
Project created = newUserWsClient(orchestrator, USER_WITH_PROVISIONING, PASSWORD).projects() | |||
.create(CreateRequest.builder().setKey(newKey).setName(newName).build()) | |||
.getProject(); | |||
assertThat(created).isNotNull(); | |||
assertThat(created.key()).isEqualTo(newKey); | |||
assertThat(created.name()).isEqualTo(newName); | |||
assertThat(created.getKey()).isEqualTo(newKey); | |||
assertThat(created.getName()).isEqualTo(newName); | |||
} | |||
/** | |||
@@ -132,11 +132,12 @@ public class ProvisioningPermissionTest { | |||
*/ | |||
@Test | |||
public void should_not_be_allowed_on_ws_without_permission() { | |||
SonarClient client = orchestrator.getServer().wsClient(USER_WITHOUT_PROVISIONING, PASSWORD); | |||
thrown.expect(HttpException.class); | |||
thrown.expectMessage("401"); | |||
client.projectClient().create(NewProject.create().key("new-project").name("New Project")); | |||
thrown.expectMessage("403"); | |||
newUserWsClient(orchestrator, USER_WITHOUT_PROVISIONING, PASSWORD).projects() | |||
.create(CreateRequest.builder().setKey("new-project").setName("New Project").build()) | |||
.getProject(); | |||
} | |||
private static void addUserPermission(String login, String permission) { |
@@ -40,7 +40,6 @@ import org.junit.Before; | |||
import org.junit.BeforeClass; | |||
import org.junit.ClassRule; | |||
import org.junit.Test; | |||
import org.sonar.wsclient.project.NewProject; | |||
import org.sonar.wsclient.qualitygate.NewCondition; | |||
import org.sonar.wsclient.qualitygate.QualityGate; | |||
import org.sonar.wsclient.qualitygate.QualityGateClient; | |||
@@ -49,6 +48,7 @@ import org.sonarqube.ws.WsCe; | |||
import org.sonarqube.ws.WsMeasures.Measure; | |||
import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse; | |||
import org.sonarqube.ws.client.GetRequest; | |||
import org.sonarqube.ws.client.PostRequest; | |||
import org.sonarqube.ws.client.WsClient; | |||
import org.sonarqube.ws.client.WsResponse; | |||
import org.sonarqube.ws.client.qualitygate.ProjectStatusWsRequest; | |||
@@ -71,8 +71,6 @@ public class QualityGateTest { | |||
private static long DEFAULT_QUALITY_GATE; | |||
private long provisionedProjectId = -1L; | |||
private static final String PROJECT_KEY = "sample"; | |||
@ClassRule | |||
@@ -91,9 +89,9 @@ public class QualityGateTest { | |||
} | |||
@Before | |||
public void cleanUp() { | |||
public void before() { | |||
orchestrator.resetData(); | |||
provisionedProjectId = Long.parseLong(orchestrator.getServer().adminWsClient().projectClient().create(NewProject.create().key(PROJECT_KEY).name("Sample")).id()); | |||
orchestrator.getServer().provisionProject(PROJECT_KEY, "Sample"); | |||
} | |||
@Test | |||
@@ -190,7 +188,7 @@ public class QualityGateTest { | |||
qgClient().createCondition(NewCondition.create(error.id()).metricKey("ncloc").operator("GT").errorThreshold("10")); | |||
qgClient().setDefault(alert.id()); | |||
qgClient().selectProject(error.id(), provisionedProjectId); | |||
associateQualityGateToProject(error.id(), PROJECT_KEY); | |||
try { | |||
SonarScanner build = SonarScanner.create(projectDir("qualitygate/xoo-sample")); | |||
@@ -303,6 +301,14 @@ public class QualityGateTest { | |||
return orchestrator.getServer().adminWsClient().qualityGateClient(); | |||
} | |||
private static void associateQualityGateToProject(long qGateId, String projectKey) { | |||
newAdminWsClient(orchestrator).wsConnector() | |||
.call(new PostRequest("api/qualitygates/select") | |||
.setParam("gateId", qGateId) | |||
.setParam("projectKey", projectKey)) | |||
.failIfNotSuccessful(); | |||
} | |||
private static List<String> extractPosttaskPluginLogs(String taskUuid, Iterable<String> ceLogs) { | |||
return StreamSupport.stream(ceLogs.spliterator(), false) | |||
.filter(s -> s.contains("POSTASKPLUGIN: finished()")) |
@@ -35,7 +35,6 @@ import org.sonar.api.server.ServerSide; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.core.component.ComponentKeys; | |||
import org.sonar.core.permission.GlobalPermissions; | |||
import org.sonar.core.util.Uuids; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
@@ -89,7 +88,6 @@ public class ComponentService { | |||
// Used by SQ and Governance | |||
public ComponentDto create(DbSession session, NewComponent newComponent) { | |||
userSession.checkPermission(GlobalPermissions.PROVISIONING); | |||
checkKeyFormat(newComponent.qualifier(), newComponent.key()); | |||
ComponentDto rootComponent = createRootComponent(session, newComponent); | |||
removeDuplicatedProjects(session, rootComponent.getKey()); |
@@ -43,6 +43,7 @@ import org.sonar.server.user.UserSession; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.lang.String.format; | |||
import static org.sonar.core.permission.GlobalPermissions.PROVISIONING; | |||
import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION; | |||
import static org.sonar.server.component.NewComponent.newComponentBuilder; | |||
import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException; | |||
@@ -97,6 +98,7 @@ public class ReportSubmitter { | |||
} | |||
private ComponentDto createProject(DbSession dbSession, String organizationUuid, String projectKey, @Nullable String projectBranch, @Nullable String projectName) { | |||
userSession.checkPermission(PROVISIONING); | |||
Integer userId = userSession.getUserId(); | |||
Long projectCreatorUserId = userId == null ? null : userId.longValue(); | |||
@@ -113,7 +115,6 @@ public class ReportSubmitter { | |||
.setBranch(projectBranch) | |||
.setQualifier(Qualifiers.PROJECT) | |||
.build(); | |||
// "provisioning" permission is check in ComponentService | |||
ComponentDto project = componentService.create(dbSession, newProject); | |||
if (permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(dbSession, organizationUuid, project)) { | |||
favoriteUpdater.add(dbSession, project); |
@@ -0,0 +1,141 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact 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.project.ws; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.server.component.ComponentService; | |||
import org.sonar.server.favorite.FavoriteUpdater; | |||
import org.sonar.server.organization.DefaultOrganizationProvider; | |||
import org.sonar.server.permission.PermissionTemplateService; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonarqube.ws.WsProjects.CreateWsResponse; | |||
import org.sonarqube.ws.client.project.CreateRequest; | |||
import static org.sonar.api.resources.Qualifiers.PROJECT; | |||
import static org.sonar.core.permission.GlobalPermissions.PROVISIONING; | |||
import static org.sonar.server.component.NewComponent.newComponentBuilder; | |||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_CREATE; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_BRANCH; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NAME; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT; | |||
public class CreateAction implements ProjectsWsAction { | |||
public static final String DEPRECATED_PARAM_KEY = "key"; | |||
private final DbClient dbClient; | |||
private final UserSession userSession; | |||
private final ComponentService componentService; | |||
private final DefaultOrganizationProvider defaultOrganizationProvider; | |||
private final PermissionTemplateService permissionTemplateService; | |||
private final FavoriteUpdater favoriteUpdater; | |||
public CreateAction(DbClient dbClient, UserSession userSession, ComponentService componentService, PermissionTemplateService permissionTemplateService, | |||
FavoriteUpdater favoriteUpdater, DefaultOrganizationProvider defaultOrganizationProvider) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
this.componentService = componentService; | |||
this.permissionTemplateService = permissionTemplateService; | |||
this.favoriteUpdater = favoriteUpdater; | |||
this.defaultOrganizationProvider = defaultOrganizationProvider; | |||
} | |||
@Override | |||
public void define(WebService.NewController context) { | |||
WebService.NewAction action = context.createAction(ACTION_CREATE) | |||
.setDescription("Create a project.<br/>" + | |||
"Requires 'Create Projects' permission<br/>" + | |||
"Since 6.3, the response has been updated and does not contain the database ID anymore") | |||
.setSince("4.0") | |||
.setPost(true) | |||
.setResponseExample(getClass().getResource("create-example.json")) | |||
.setHandler(this); | |||
action.createParam(PARAM_PROJECT) | |||
.setDescription("Key of the project") | |||
.setDeprecatedKey(DEPRECATED_PARAM_KEY) | |||
.setRequired(true) | |||
.setExampleValue(KEY_PROJECT_EXAMPLE_001); | |||
action.createParam(PARAM_NAME) | |||
.setDescription("Name of the project") | |||
.setRequired(true) | |||
.setExampleValue("SonarQube"); | |||
action.createParam(PARAM_BRANCH) | |||
.setDescription("SCM Branch of the project. The key of the project will become key:branch, for instance 'SonarQube:branch-5.0'") | |||
.setExampleValue("branch-5.0"); | |||
} | |||
@Override | |||
public void handle(Request request, Response response) throws Exception { | |||
userSession.checkPermission(PROVISIONING); | |||
CreateRequest createRequest = toCreateRequest(request); | |||
writeProtobuf(doHandle(createRequest), request, response); | |||
} | |||
private CreateWsResponse doHandle(CreateRequest request) { | |||
String organizationUuid = defaultOrganizationProvider.get().getUuid(); | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
ComponentDto componentDto = componentService.create(dbSession, newComponentBuilder() | |||
.setOrganizationUuid(organizationUuid) | |||
.setKey(request.getKey()) | |||
.setName(request.getName()) | |||
.setBranch(request.getBranch()) | |||
.setQualifier(PROJECT) | |||
.build()); | |||
handlePermissionTemplate(dbSession, componentDto, organizationUuid); | |||
return toCreateResponse(componentDto); | |||
} | |||
} | |||
private void handlePermissionTemplate(DbSession dbSession, ComponentDto componentDto, String organizationUuid) { | |||
permissionTemplateService.applyDefault(dbSession, organizationUuid, componentDto, userSession.isLoggedIn() ? userSession.getUserId().longValue() : null); | |||
if (permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(dbSession, organizationUuid, componentDto)) { | |||
favoriteUpdater.add(dbSession, componentDto); | |||
dbSession.commit(); | |||
} | |||
} | |||
private static CreateRequest toCreateRequest(Request request) { | |||
return CreateRequest.builder() | |||
.setKey(request.mandatoryParam(PARAM_PROJECT)) | |||
.setName(request.mandatoryParam(PARAM_NAME)) | |||
.setBranch(request.param(PARAM_BRANCH)) | |||
.build(); | |||
} | |||
private static CreateWsResponse toCreateResponse(ComponentDto componentDto) { | |||
return CreateWsResponse.newBuilder() | |||
.setProject(CreateWsResponse.Project.newBuilder() | |||
.setKey(componentDto.key()) | |||
.setName(componentDto.name()) | |||
.setQualifier(componentDto.qualifier())) | |||
.build(); | |||
} | |||
} |
@@ -20,6 +20,7 @@ | |||
package org.sonar.server.project.ws; | |||
import com.google.common.io.Resources; | |||
import java.util.Arrays; | |||
import org.sonar.api.server.ws.RailsHandler; | |||
import org.sonar.api.server.ws.WebService; | |||
@@ -43,12 +44,7 @@ public class ProjectsWs implements WebService { | |||
.setDescription("Manage project existence."); | |||
defineIndexAction(controller); | |||
defineCreateAction(controller); | |||
for (ProjectsWsAction action : actions) { | |||
action.define(controller); | |||
} | |||
Arrays.stream(actions).forEach(action -> action.define(controller)); | |||
controller.done(); | |||
} | |||
@@ -95,29 +91,4 @@ public class ProjectsWs implements WebService { | |||
RailsHandler.addFormatParam(action); | |||
} | |||
private void defineCreateAction(NewController controller) { | |||
WebService.NewAction action = controller.createAction("create") | |||
.setDescription("Create a project. Requires Create Projects permission") | |||
.setSince("4.0") | |||
.setPost(true) | |||
.setHandler(RailsHandler.INSTANCE) | |||
.setResponseExample(Resources.getResource(this.getClass(), "projects-example-create.json")); | |||
action.createParam("key") | |||
.setDescription("Key of the project") | |||
.setRequired(true) | |||
.setExampleValue(KEY_PROJECT_EXAMPLE_001); | |||
action.createParam("name") | |||
.setDescription("Name of the project") | |||
.setRequired(true) | |||
.setExampleValue("SonarQube"); | |||
action.createParam("branch") | |||
.setDescription("SCM Branch of the project. The key of the project will become key:branch, for instance 'SonarQube:branch-5.0'") | |||
.setRequired(false) | |||
.setExampleValue("branch-5.0"); | |||
RailsHandler.addFormatParam(action); | |||
} | |||
} |
@@ -26,6 +26,7 @@ public class ProjectsWsModule extends Module { | |||
protected void configureModule() { | |||
add( | |||
ProjectsWs.class, | |||
CreateAction.class, | |||
BulkDeleteAction.class, | |||
DeleteAction.class, | |||
GhostsAction.class, |
@@ -0,0 +1,7 @@ | |||
{ | |||
"project": { | |||
"key": "project-key", | |||
"name": "project-name", | |||
"qualifier": "TRK" | |||
} | |||
} |
@@ -1,8 +0,0 @@ | |||
{ | |||
"id": "30057", | |||
"k": "org.jenkins-ci.plugins:sonar", | |||
"nm": "Jenkins Sonar Plugin", | |||
"sc": "PRJ", | |||
"qu": "TRK" | |||
} | |||
@@ -26,9 +26,12 @@ import java.util.Locale; | |||
import java.util.Map; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.junit.rules.TestRule; | |||
import org.junit.runner.Description; | |||
import org.junit.runners.model.Statement; | |||
import org.sonar.api.i18n.I18n; | |||
public class I18nRule implements I18n { | |||
public class I18nRule implements TestRule, I18n { | |||
private final Map<String, String> messages = new HashMap<>(); | |||
public I18nRule put(String key, String value) { | |||
@@ -36,6 +39,20 @@ public class I18nRule implements I18n { | |||
return this; | |||
} | |||
@Override | |||
public Statement apply(final Statement statement, Description description) { | |||
return new Statement() { | |||
@Override | |||
public void evaluate() throws Throwable { | |||
try { | |||
statement.evaluate(); | |||
} finally { | |||
messages.clear(); | |||
} | |||
} | |||
}; | |||
} | |||
public void setProjectPermissions() { | |||
put("projects_role.admin", "Administer"); | |||
put("projects_role.admin.desc", "Ability to access project settings and perform administration tasks. " + | |||
@@ -101,4 +118,5 @@ public class I18nRule implements I18n { | |||
public String formatInteger(Locale locale, Integer value) { | |||
return String.valueOf(value); | |||
} | |||
} |
@@ -0,0 +1,322 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact 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.project.ws; | |||
import com.google.common.base.Throwables; | |||
import java.io.IOException; | |||
import org.assertj.core.api.Assertions; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.config.MapSettings; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.db.permission.template.PermissionTemplateDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.server.component.ComponentService; | |||
import org.sonar.server.component.index.ComponentIndexDefinition; | |||
import org.sonar.server.component.index.ComponentIndexer; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.favorite.FavoriteUpdater; | |||
import org.sonar.server.i18n.I18nRule; | |||
import org.sonar.server.measure.index.ProjectMeasuresIndexDefinition; | |||
import org.sonar.server.measure.index.ProjectMeasuresIndexer; | |||
import org.sonar.server.organization.DefaultOrganizationProvider; | |||
import org.sonar.server.organization.TestDefaultOrganizationProvider; | |||
import org.sonar.server.permission.PermissionTemplateService; | |||
import org.sonar.server.permission.index.PermissionIndexer; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.ws.TestRequest; | |||
import org.sonar.server.ws.WsActionTester; | |||
import org.sonarqube.ws.MediaTypes; | |||
import org.sonarqube.ws.WsProjects.CreateWsResponse; | |||
import org.sonarqube.ws.client.project.CreateRequest; | |||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; | |||
import static org.sonar.api.web.UserRole.USER; | |||
import static org.sonar.core.permission.GlobalPermissions.PROVISIONING; | |||
import static org.sonar.core.permission.GlobalPermissions.QUALITY_GATE_ADMIN; | |||
import static org.sonar.core.util.Protobuf.setNullable; | |||
import static org.sonar.server.component.index.ComponentIndexDefinition.INDEX_COMPONENTS; | |||
import static org.sonar.server.component.index.ComponentIndexDefinition.TYPE_COMPONENT; | |||
import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES; | |||
import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURE; | |||
import static org.sonar.test.JsonAssert.assertJson; | |||
import static org.sonarqube.ws.client.WsRequest.Method.POST; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NAME; | |||
public class CreateActionTest { | |||
private static final String DEFAULT_PROJECT_KEY = "project-key"; | |||
private static final String DEFAULT_PROJECT_NAME = "project-name"; | |||
private System2 system2 = System2.INSTANCE; | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public DbTester db = DbTester.create(system2); | |||
@Rule | |||
public EsTester es = new EsTester(new ComponentIndexDefinition(new MapSettings()), new ProjectMeasuresIndexDefinition(new MapSettings())); | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
@Rule | |||
public I18nRule i18n = new I18nRule().put("qualifier.TRK", "Project"); | |||
private Settings settings = new MapSettings(); | |||
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); | |||
private PermissionTemplateDto permissionTemplateDto; | |||
private WsActionTester ws = new WsActionTester( | |||
new CreateAction( | |||
db.getDbClient(), userSession, | |||
new ComponentService(db.getDbClient(), i18n, userSession, system2, | |||
new ProjectMeasuresIndexer(system2, db.getDbClient(), es.client()), | |||
new ComponentIndexer(db.getDbClient(), es.client())), | |||
new PermissionTemplateService(db.getDbClient(), settings, new PermissionIndexer(db.getDbClient(), es.client()), userSession), | |||
new FavoriteUpdater(db.getDbClient(), userSession), | |||
defaultOrganizationProvider)); | |||
@Before | |||
public void setUp() throws Exception { | |||
permissionTemplateDto = db.permissionTemplates().insertTemplate(); | |||
setTemplateAsDefault(permissionTemplateDto); | |||
} | |||
@Test | |||
public void create_project() throws Exception { | |||
userSession.setGlobalPermissions(PROVISIONING); | |||
CreateWsResponse response = call(CreateRequest.builder() | |||
.setKey(DEFAULT_PROJECT_KEY) | |||
.setName(DEFAULT_PROJECT_NAME) | |||
.build()); | |||
assertThat(response.getProject().getKey()).isEqualTo(DEFAULT_PROJECT_KEY); | |||
assertThat(response.getProject().getName()).isEqualTo(DEFAULT_PROJECT_NAME); | |||
assertThat(response.getProject().getQualifier()).isEqualTo("TRK"); | |||
ComponentDto project = db.getDbClient().componentDao().selectOrFailByKey(db.getSession(), DEFAULT_PROJECT_KEY); | |||
assertThat(project.getKey()).isEqualTo(DEFAULT_PROJECT_KEY); | |||
assertThat(project.name()).isEqualTo(DEFAULT_PROJECT_NAME); | |||
assertThat(project.qualifier()).isEqualTo("TRK"); | |||
} | |||
@Test | |||
public void create_project_with_branch() throws Exception { | |||
userSession.setGlobalPermissions(PROVISIONING); | |||
CreateWsResponse response = call(CreateRequest.builder() | |||
.setKey(DEFAULT_PROJECT_KEY) | |||
.setName(DEFAULT_PROJECT_NAME) | |||
.setBranch("origin/master") | |||
.build()); | |||
assertThat(response.getProject().getKey()).isEqualTo("project-key:origin/master"); | |||
} | |||
@Test | |||
public void verify_permission_template_is_applied() throws Exception { | |||
UserDto userDto = db.users().insertUser(); | |||
userSession.login(userDto).setGlobalPermissions(PROVISIONING); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplateDto.getId(), userDto.getId(), USER); | |||
call(CreateRequest.builder() | |||
.setKey(DEFAULT_PROJECT_KEY) | |||
.setName(DEFAULT_PROJECT_NAME) | |||
.build()); | |||
ComponentDto project = db.getDbClient().componentDao().selectOrFailByKey(db.getSession(), DEFAULT_PROJECT_KEY); | |||
assertThat(db.users().selectProjectPermissionsOfUser(userDto, project)).containsOnly(USER); | |||
} | |||
@Test | |||
public void add_project_to_favorite_when_logged() throws Exception { | |||
UserDto userDto = db.users().insertUser(); | |||
userSession.login(userDto).setGlobalPermissions(PROVISIONING); | |||
db.permissionTemplates().addProjectCreatorToTemplate(permissionTemplateDto.getId(), USER); | |||
call(CreateRequest.builder() | |||
.setKey(DEFAULT_PROJECT_KEY) | |||
.setName(DEFAULT_PROJECT_NAME) | |||
.build()); | |||
ComponentDto project = db.getDbClient().componentDao().selectOrFailByKey(db.getSession(), DEFAULT_PROJECT_KEY); | |||
assertThat(db.favorites().hasFavorite(project, userDto.getId())).isTrue(); | |||
} | |||
@Test | |||
public void does_not_add_project_to_favorite_when_not_logged() throws Exception { | |||
userSession.setGlobalPermissions(PROVISIONING); | |||
db.permissionTemplates().addProjectCreatorToTemplate(permissionTemplateDto.getId(), USER); | |||
call(CreateRequest.builder() | |||
.setKey(DEFAULT_PROJECT_KEY) | |||
.setName(DEFAULT_PROJECT_NAME) | |||
.build()); | |||
ComponentDto project = db.getDbClient().componentDao().selectOrFailByKey(db.getSession(), DEFAULT_PROJECT_KEY); | |||
assertThat(db.favorites().hasNoFavorite(project)).isTrue(); | |||
} | |||
@Test | |||
public void does_not_add_project_to_favorite_when_project_create_has_no_permission_on_template() throws Exception { | |||
UserDto userDto = db.users().insertUser(); | |||
userSession.login(userDto).setGlobalPermissions(PROVISIONING); | |||
call(CreateRequest.builder() | |||
.setKey(DEFAULT_PROJECT_KEY) | |||
.setName(DEFAULT_PROJECT_NAME) | |||
.build()); | |||
ComponentDto project = db.getDbClient().componentDao().selectOrFailByKey(db.getSession(), DEFAULT_PROJECT_KEY); | |||
assertThat(db.favorites().hasNoFavorite(project)).isTrue(); | |||
} | |||
@Test | |||
public void verify_project_exists_in_es_indexes() throws Exception { | |||
userSession.setGlobalPermissions(PROVISIONING); | |||
call(CreateRequest.builder() | |||
.setKey(DEFAULT_PROJECT_KEY) | |||
.setName(DEFAULT_PROJECT_NAME) | |||
.build()); | |||
ComponentDto project = db.getDbClient().componentDao().selectOrFailByKey(db.getSession(), DEFAULT_PROJECT_KEY); | |||
assertThat(es.getIds(INDEX_COMPONENTS, TYPE_COMPONENT)).containsOnly(project.uuid()); | |||
assertThat(es.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURE)).containsOnly(project.uuid()); | |||
} | |||
@Test | |||
public void create_project_with_deprecated_parameter() throws Exception { | |||
userSession.setGlobalPermissions(PROVISIONING); | |||
ws.newRequest() | |||
.setMethod(POST.name()) | |||
.setParam("key", DEFAULT_PROJECT_KEY) | |||
.setParam(PARAM_NAME, DEFAULT_PROJECT_NAME) | |||
.execute(); | |||
assertThat(db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY).isPresent()).isTrue(); | |||
} | |||
@Test | |||
public void fail_when_project_already_exists() throws Exception { | |||
userSession.setGlobalPermissions(PROVISIONING); | |||
db.components().insertComponent(ComponentTesting.newProjectDto(db.getDefaultOrganization()).setKey(DEFAULT_PROJECT_KEY)); | |||
expectedException.expect(BadRequestException.class); | |||
expectedException.expectMessage("Could not create Project, key already exists: project-key"); | |||
call(CreateRequest.builder() | |||
.setKey(DEFAULT_PROJECT_KEY) | |||
.setName(DEFAULT_PROJECT_NAME) | |||
.build()); | |||
} | |||
@Test | |||
public void fail_when_missing_project_parameter() throws Exception { | |||
userSession.setGlobalPermissions(PROVISIONING); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("The 'project' parameter is missing"); | |||
call(CreateRequest.builder().setName(DEFAULT_PROJECT_NAME).build()); | |||
} | |||
@Test | |||
public void fail_when_missing_name_parameter() throws Exception { | |||
userSession.setGlobalPermissions(PROVISIONING); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("The 'name' parameter is missing"); | |||
call(CreateRequest.builder().setKey(DEFAULT_PROJECT_KEY).build()); | |||
} | |||
@Test | |||
public void fail_when_key_has_bad_format() throws Exception { | |||
userSession.setGlobalPermissions(PROVISIONING); | |||
expectedException.expect(BadRequestException.class); | |||
expectedException.expectMessage("Malformed key for Project: 1234"); | |||
call(CreateRequest.builder().setKey("1234").setName(DEFAULT_PROJECT_NAME).build()); | |||
} | |||
@Test | |||
public void fail_when_missing_create_project_permission() throws Exception { | |||
userSession.setGlobalPermissions(QUALITY_GATE_ADMIN); | |||
expectedException.expect(ForbiddenException.class); | |||
call(CreateRequest.builder().setKey(DEFAULT_PROJECT_KEY).setName(DEFAULT_PROJECT_NAME).build()); | |||
} | |||
@Test | |||
public void test_example() { | |||
userSession.setGlobalPermissions(PROVISIONING); | |||
String result = ws.newRequest() | |||
.setParam("key", DEFAULT_PROJECT_KEY) | |||
.setParam("name", DEFAULT_PROJECT_NAME) | |||
.execute().getInput(); | |||
assertJson(result).isSimilarTo(getClass().getResource("create-example.json")); | |||
} | |||
@Test | |||
public void definition() { | |||
WebService.Action definition = ws.getDef(); | |||
Assertions.assertThat(definition.key()).isEqualTo("create"); | |||
Assertions.assertThat(definition.since()).isEqualTo("4.0"); | |||
Assertions.assertThat(definition.isInternal()).isFalse(); | |||
Assertions.assertThat(definition.responseExampleAsString()).isNotEmpty(); | |||
Assertions.assertThat(definition.params()).hasSize(3); | |||
} | |||
private CreateWsResponse call(CreateRequest request) { | |||
TestRequest httpRequest = ws.newRequest() | |||
.setMethod(POST.name()) | |||
.setMediaType(MediaTypes.PROTOBUF); | |||
setNullable(request.getKey(), e -> httpRequest.setParam("project", e)); | |||
setNullable(request.getName(), e -> httpRequest.setParam("name", e)); | |||
setNullable(request.getBranch(), e -> httpRequest.setParam("branch", e)); | |||
try { | |||
return CreateWsResponse.parseFrom(httpRequest.execute().getInputStream()); | |||
} catch (IOException e) { | |||
throw Throwables.propagate(e); | |||
} | |||
} | |||
private void setTemplateAsDefault(PermissionTemplateDto permissionTemplateDto) { | |||
settings.appendProperty("sonar.permission.template.default", permissionTemplateDto.getUuid()); | |||
} | |||
} |
@@ -29,6 +29,6 @@ public class ProjectsWsModuleTest { | |||
public void verify_count_of_added_components() { | |||
ComponentContainer container = new ComponentContainer(); | |||
new ProjectsWsModule().configure(container); | |||
assertThat(container.size()).isEqualTo(2 + 7); | |||
assertThat(container.size()).isEqualTo(2 + 8); | |||
} | |||
} |
@@ -41,8 +41,7 @@ public class ProjectsWsTest { | |||
ws = new WsTester(new ProjectsWs( | |||
new BulkDeleteAction(mock(ComponentCleanerService.class), mock(DbClient.class), mock(UserSession.class)), | |||
new GhostsAction(mock(DbClient.class), mock(UserSession.class)), | |||
new ProvisionedAction(mock(DbClient.class), mock(UserSession.class)) | |||
)); | |||
new ProvisionedAction(mock(DbClient.class), mock(UserSession.class)))); | |||
controller = ws.controller("api/projects"); | |||
} | |||
@@ -51,7 +50,7 @@ public class ProjectsWsTest { | |||
assertThat(controller).isNotNull(); | |||
assertThat(controller.description()).isNotEmpty(); | |||
assertThat(controller.since()).isEqualTo("2.10"); | |||
assertThat(controller.actions()).hasSize(5); | |||
assertThat(controller.actions()).hasSize(4); | |||
} | |||
@Test | |||
@@ -63,12 +62,4 @@ public class ProjectsWsTest { | |||
assertThat(action.params()).hasSize(8); | |||
} | |||
@Test | |||
public void define_create_action() { | |||
WebService.Action action = controller.action("create"); | |||
assertThat(action).isNotNull(); | |||
assertThat(action.handler()).isInstanceOf(RailsHandler.class); | |||
assertThat(action.responseExampleAsString()).isNotEmpty(); | |||
assertThat(action.params()).hasSize(4); | |||
} | |||
} |
@@ -31,12 +31,10 @@ import org.sonar.db.property.PropertyQuery; | |||
public class FavoriteDbTester { | |||
private static final String PROP_FAVORITE_KEY = "favourite"; | |||
private final DbTester db; | |||
private final DbClient dbClient; | |||
private final DbSession dbSession; | |||
public FavoriteDbTester(DbTester db) { | |||
this.db = db; | |||
this.dbClient = db.getDbClient(); | |||
this.dbSession = db.getSession(); | |||
} | |||
@@ -58,4 +56,12 @@ public class FavoriteDbTester { | |||
return !result.isEmpty(); | |||
} | |||
public boolean hasNoFavorite(ComponentDto componentDto) { | |||
List<PropertyDto> result = dbClient.propertiesDao().selectByQuery(PropertyQuery.builder() | |||
.setKey(PROP_FAVORITE_KEY) | |||
.setComponentId(componentDto.getId()) | |||
.build(), dbSession); | |||
return result.isEmpty(); | |||
} | |||
} |
@@ -20,10 +20,17 @@ | |||
package org.sonarqube.ws.client.project; | |||
import org.sonarqube.ws.WsProjects.CreateWsResponse; | |||
import org.sonarqube.ws.client.BaseService; | |||
import org.sonarqube.ws.client.PostRequest; | |||
import org.sonarqube.ws.client.WsConnector; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_CREATE; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.CONTROLLER; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_BRANCH; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NAME; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT; | |||
/** | |||
* Maps web service {@code api/projects}. | |||
* @since 5.5 | |||
@@ -31,7 +38,7 @@ import org.sonarqube.ws.client.WsConnector; | |||
public class ProjectsService extends BaseService { | |||
public ProjectsService(WsConnector wsConnector) { | |||
super(wsConnector, "api/projects"); | |||
super(wsConnector, CONTROLLER); | |||
} | |||
/** | |||
@@ -39,12 +46,12 @@ public class ProjectsService extends BaseService { | |||
* | |||
* @throws org.sonarqube.ws.client.HttpException if HTTP status code is not 2xx. | |||
*/ | |||
public void create(CreateRequest project) { | |||
PostRequest request = new PostRequest(path("create")) | |||
.setParam("key", project.getKey()) | |||
.setParam("name", project.getName()) | |||
.setParam("branch", project.getBranch()); | |||
call(request); | |||
public CreateWsResponse create(CreateRequest project) { | |||
PostRequest request = new PostRequest(path(ACTION_CREATE)) | |||
.setParam(PARAM_PROJECT, project.getKey()) | |||
.setParam(PARAM_NAME, project.getName()) | |||
.setParam(PARAM_BRANCH, project.getBranch()); | |||
return call(request, CreateWsResponse.parser()); | |||
} | |||
/** |
@@ -0,0 +1,35 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact 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.sonarqube.ws.client.project; | |||
public class ProjectsWsParameters { | |||
public static final String CONTROLLER = "api/projects"; | |||
public static final String ACTION_CREATE = "create"; | |||
public static final String PARAM_PROJECT = "project"; | |||
public static final String PARAM_NAME = "name"; | |||
public static final String PARAM_BRANCH = "branch"; | |||
private ProjectsWsParameters() { | |||
// static utils only | |||
} | |||
} |
@@ -46,3 +46,14 @@ message SearchMyProjectsWsResponse { | |||
optional sonarqube.ws.commons.Paging paging = 1; | |||
repeated Project projects = 2; | |||
} | |||
message CreateWsResponse { | |||
optional Project project = 1; | |||
message Project { | |||
optional string key = 1; | |||
optional string name = 2; | |||
optional string qualifier = 3; | |||
} | |||
} | |||
@@ -21,6 +21,7 @@ package org.sonarqube.ws.client.project; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonarqube.ws.WsProjects; | |||
import org.sonarqube.ws.client.ServiceTester; | |||
import org.sonarqube.ws.client.WsConnector; | |||
@@ -42,9 +43,10 @@ public class ProjectsServiceTest { | |||
.setName("Project Name") | |||
.build()); | |||
assertThat(serviceTester.getPostParser()).isSameAs(WsProjects.CreateWsResponse.parser()); | |||
assertThat(serviceTester.getPostRequest().getPath()).isEqualTo("api/projects/create"); | |||
assertThat(serviceTester.getPostRequest().getParams()).containsOnly( | |||
entry("key", "project_key"), | |||
entry("project", "project_key"), | |||
entry("name", "Project Name")); | |||
} | |||
@@ -58,7 +60,7 @@ public class ProjectsServiceTest { | |||
assertThat(serviceTester.getPostRequest().getPath()).isEqualTo("api/projects/create"); | |||
assertThat(serviceTester.getPostRequest().getParams()).containsOnly( | |||
entry("key", "project_key"), | |||
entry("project", "project_key"), | |||
entry("name", "Project Name"), | |||
entry("branch", "the_branch")); | |||
} |