]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8651 add organization parameter to api/projects/create 1605/head
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Tue, 31 Jan 2017 13:02:10 +0000 (14:02 +0100)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 2 Feb 2017 15:12:13 +0000 (16:12 +0100)
server/sonar-server/src/main/java/org/sonar/server/project/ws/CreateAction.java
server/sonar-server/src/main/java/org/sonar/server/project/ws/ProjectsWsSupport.java
server/sonar-server/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java
server/sonar-server/src/test/java/org/sonar/server/project/ws/CreateActionTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/project/CreateRequest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/project/ProjectsService.java
sonar-ws/src/test/java/org/sonarqube/ws/client/project/ProjectsServiceTest.java

index 4267b349a9a692e66d35bc8e5ef7890293649013..2ffa96b7c037b0ae60b17c58eac7ea3a22d38613 100644 (file)
@@ -25,15 +25,18 @@ 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.db.organization.OrganizationDto;
 import org.sonar.server.component.ComponentUpdater;
 import org.sonar.server.organization.DefaultOrganizationProvider;
 import org.sonar.server.user.UserSession;
 import org.sonarqube.ws.WsProjects.CreateWsResponse;
 import org.sonarqube.ws.client.project.CreateRequest;
 
+import static java.util.Optional.ofNullable;
 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.project.ws.ProjectsWsSupport.PARAM_ORGANIZATION;
 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;
@@ -43,14 +46,17 @@ import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT
 
 public class CreateAction implements ProjectsWsAction {
 
-  public static final String DEPRECATED_PARAM_KEY = "key";
+  private static final String DEPRECATED_PARAM_KEY = "key";
 
+  private final ProjectsWsSupport support;
   private final DbClient dbClient;
   private final UserSession userSession;
   private final ComponentUpdater componentUpdater;
   private final DefaultOrganizationProvider defaultOrganizationProvider;
 
-  public CreateAction(DbClient dbClient, UserSession userSession, ComponentUpdater componentUpdater, DefaultOrganizationProvider defaultOrganizationProvider) {
+  public CreateAction(ProjectsWsSupport support, DbClient dbClient, UserSession userSession, ComponentUpdater componentUpdater,
+    DefaultOrganizationProvider defaultOrganizationProvider) {
+    this.support = support;
     this.dbClient = dbClient;
     this.userSession = userSession;
     this.componentUpdater = componentUpdater;
@@ -83,19 +89,24 @@ public class CreateAction implements ProjectsWsAction {
     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");
+
+    support.addOrganizationParam(action);
   }
 
   @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) {
     try (DbSession dbSession = dbClient.openSession(false)) {
+      OrganizationDto organization = support.getOrganization(dbSession, ofNullable(request.getOrganization())
+        .orElseGet(defaultOrganizationProvider.get()::getKey));
+      userSession.checkOrganizationPermission(organization.getUuid(), PROVISIONING);
+
       ComponentDto componentDto = componentUpdater.create(dbSession, newComponentBuilder()
-        .setOrganizationUuid(defaultOrganizationProvider.get().getUuid())
+        .setOrganizationUuid(organization.getUuid())
         .setKey(request.getKey())
         .setName(request.getName())
         .setBranch(request.getBranch())
@@ -108,6 +119,7 @@ public class CreateAction implements ProjectsWsAction {
 
   private static CreateRequest toCreateRequest(Request request) {
     return CreateRequest.builder()
+      .setOrganization(request.param(PARAM_ORGANIZATION))
       .setKey(request.mandatoryParam(PARAM_PROJECT))
       .setName(request.mandatoryParam(PARAM_NAME))
       .setBranch(request.param(PARAM_BRANCH))
index e587cbfff338f6a827078f65608960c65b797b61..813cb6d101da8ea76bfe46c1db3fff519c2f7d1a 100644 (file)
@@ -27,7 +27,7 @@ import org.sonar.db.organization.OrganizationDto;
 import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
 
 public class ProjectsWsSupport {
-  static final String PARAM_ORGANIZATION = "organization";
+  public static final String PARAM_ORGANIZATION = "organization";
 
   private final DbClient dbClient;
 
index 5442ad996d3d70cbf8c49a2ed3b66b93c99244bb..541aebe1e7e6172743dddef1f5f39694a13e15c2 100644 (file)
@@ -179,6 +179,22 @@ public class ComponentUpdaterTest {
         null);
   }
 
+  @Test
+  public void fail_when_project_key_already_exists_on_other_organization() throws Exception {
+    ComponentDto existing = db.components().insertProject(db.organizations().insert());
+
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("Could not create Project, key already exists: " + existing.key());
+
+    underTest.create(db.getSession(),
+        NewComponent.newComponentBuilder()
+            .setKey(existing.key())
+            .setName(DEFAULT_PROJECT_NAME)
+            .setOrganizationUuid(existing.getOrganizationUuid())
+            .build(),
+        null);
+  }
+
   @Test
   public void fail_when_key_has_bad_format() throws Exception {
     expectedException.expect(BadRequestException.class);
index 7a7411062e25b577174c89b0c1d3c08bf941f8ee..3e0ee7ad05bccdc70968221226550cafccdecf67 100644 (file)
@@ -32,6 +32,7 @@ import org.sonar.api.utils.System2;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
+import org.sonar.db.organization.OrganizationDto;
 import org.sonar.server.component.ComponentUpdater;
 import org.sonar.server.component.NewComponent;
 import org.sonar.server.exceptions.BadRequestException;
@@ -54,6 +55,7 @@ import static org.mockito.Mockito.when;
 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.project.ws.ProjectsWsSupport.PARAM_ORGANIZATION;
 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;
@@ -71,24 +73,26 @@ public class CreateActionTest {
   public DbTester db = DbTester.create(system2);
   @Rule
   public UserSessionRule userSession = UserSessionRule.standalone();
+
   private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
   private ComponentUpdater componentUpdater = mock(ComponentUpdater.class, Mockito.RETURNS_MOCKS);
 
   private WsActionTester ws = new WsActionTester(
-      new CreateAction(
-          db.getDbClient(), userSession,
-          componentUpdater,
-          defaultOrganizationProvider));
+    new CreateAction(
+      new ProjectsWsSupport(db.getDbClient()),
+      db.getDbClient(), userSession,
+      componentUpdater,
+      defaultOrganizationProvider));
 
   @Test
   public void create_project() throws Exception {
-    userSession.setGlobalPermissions(PROVISIONING);
+    userSession.addOrganizationPermission(db.getDefaultOrganization(), PROVISIONING);
     expectSuccessfulCallToComponentUpdater();
 
     CreateWsResponse response = call(CreateRequest.builder()
-        .setKey(DEFAULT_PROJECT_KEY)
-        .setName(DEFAULT_PROJECT_NAME)
-        .build());
+      .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);
@@ -97,13 +101,13 @@ public class CreateActionTest {
 
   @Test
   public void create_project_with_branch() throws Exception {
-    userSession.setGlobalPermissions(PROVISIONING);
+    userSession.addOrganizationPermission(db.getDefaultOrganization(), PROVISIONING);
 
     call(CreateRequest.builder()
-        .setKey(DEFAULT_PROJECT_KEY)
-        .setName(DEFAULT_PROJECT_NAME)
-        .setBranch("origin/master")
-        .build());
+      .setKey(DEFAULT_PROJECT_KEY)
+      .setName(DEFAULT_PROJECT_NAME)
+      .setBranch("origin/master")
+      .build());
 
     NewComponent called = verifyCallToComponentUpdater();
     assertThat(called.key()).isEqualTo(DEFAULT_PROJECT_KEY);
@@ -112,13 +116,15 @@ public class CreateActionTest {
 
   @Test
   public void create_project_with_deprecated_parameter() throws Exception {
-    userSession.setGlobalPermissions(PROVISIONING);
+    OrganizationDto organization = db.organizations().insert();
+    userSession.addOrganizationPermission(organization, PROVISIONING);
 
     ws.newRequest()
-        .setMethod(POST.name())
-        .setParam("key", DEFAULT_PROJECT_KEY)
-        .setParam(PARAM_NAME, DEFAULT_PROJECT_NAME)
-        .execute();
+      .setMethod(POST.name())
+      .setParam("organization", organization.getKey())
+      .setParam("key", DEFAULT_PROJECT_KEY)
+      .setParam(PARAM_NAME, DEFAULT_PROJECT_NAME)
+      .execute();
 
     NewComponent called = verifyCallToComponentUpdater();
     assertThat(called.key()).isEqualTo(DEFAULT_PROJECT_KEY);
@@ -127,15 +133,17 @@ public class CreateActionTest {
 
   @Test
   public void fail_when_project_already_exists() throws Exception {
-    userSession.setGlobalPermissions(PROVISIONING);
+    OrganizationDto organization = db.organizations().insert();
     when(componentUpdater.create(any(DbSession.class), any(NewComponent.class), anyLong())).thenThrow(new BadRequestException("already exists"));
+    userSession.addOrganizationPermission(organization, PROVISIONING);
 
     expectedException.expect(BadRequestException.class);
 
     call(CreateRequest.builder()
-        .setKey(DEFAULT_PROJECT_KEY)
-        .setName(DEFAULT_PROJECT_NAME)
-        .build());
+      .setOrganization(organization.getKey())
+      .setKey(DEFAULT_PROJECT_KEY)
+      .setName(DEFAULT_PROJECT_NAME)
+      .build());
   }
 
   @Test
@@ -166,13 +174,13 @@ public class CreateActionTest {
 
   @Test
   public void test_example() {
-    userSession.setGlobalPermissions(PROVISIONING);
+    userSession.addOrganizationPermission(db.getDefaultOrganization(), PROVISIONING);
     expectSuccessfulCallToComponentUpdater();
 
     String result = ws.newRequest()
-        .setParam("key", DEFAULT_PROJECT_KEY)
-        .setParam("name", DEFAULT_PROJECT_NAME)
-        .execute().getInput();
+      .setParam("key", DEFAULT_PROJECT_KEY)
+      .setParam("name", DEFAULT_PROJECT_NAME)
+      .execute().getInput();
 
     assertJson(result).isSimilarTo(getClass().getResource("create-example.json"));
   }
@@ -185,13 +193,21 @@ public class CreateActionTest {
     Assertions.assertThat(definition.since()).isEqualTo("4.0");
     Assertions.assertThat(definition.isInternal()).isFalse();
     Assertions.assertThat(definition.responseExampleAsString()).isNotEmpty();
-    Assertions.assertThat(definition.params()).hasSize(3);
+
+    Assertions.assertThat(definition.params()).hasSize(4);
+
+    WebService.Param organization = definition.param(PARAM_ORGANIZATION);
+    Assertions.assertThat(organization.description()).isEqualTo("The key of the organization");
+    Assertions.assertThat(organization.isInternal()).isTrue();
+    Assertions.assertThat(organization.isRequired()).isFalse();
+    Assertions.assertThat(organization.since()).isEqualTo("6.3");
   }
 
   private CreateWsResponse call(CreateRequest request) {
     TestRequest httpRequest = ws.newRequest()
-        .setMethod(POST.name())
-        .setMediaType(MediaTypes.PROTOBUF);
+      .setMethod(POST.name())
+      .setMediaType(MediaTypes.PROTOBUF);
+    setNullable(request.getOrganization(), e -> httpRequest.setParam("organization", e));
     setNullable(request.getKey(), e -> httpRequest.setParam("project", e));
     setNullable(request.getName(), e -> httpRequest.setParam("name", e));
     setNullable(request.getBranch(), e -> httpRequest.setParam("branch", e));
index b68e7746999663c6c20313535af1ea36dc43d2c9..06ab43c227045e2264f5f3e34e8bde9eda866df8 100644 (file)
@@ -26,16 +26,23 @@ import javax.annotation.concurrent.Immutable;
 @Immutable
 public class CreateRequest {
 
+  private final String organization;
   private final String key;
   private final String name;
   private final String branch;
 
   private CreateRequest(Builder builder) {
+    this.organization = builder.organization;
     this.key = builder.key;
     this.name = builder.name;
     this.branch = builder.branch;
   }
 
+  @CheckForNull
+  public String getOrganization() {
+    return organization;
+  }
+
   public String getKey() {
     return key;
   }
@@ -54,6 +61,7 @@ public class CreateRequest {
   }
 
   public static class Builder {
+    private String organization;
     private String key;
     private String name;
     private String branch;
@@ -61,6 +69,11 @@ public class CreateRequest {
     private Builder() {
     }
 
+    public Builder setOrganization(String organization) {
+      this.organization = organization;
+      return this;
+    }
+
     public Builder setKey(String key) {
       this.key = key;
       return this;
index 37f0db639a748f433fc6242965e448c707313432..328045fbd868b875e109cd7e468d2aead41abdb6 100644 (file)
@@ -48,6 +48,7 @@ public class ProjectsService extends BaseService {
    */
   public CreateWsResponse create(CreateRequest project) {
     PostRequest request = new PostRequest(path(ACTION_CREATE))
+      .setParam("organization", project.getOrganization())
       .setParam(PARAM_PROJECT, project.getKey())
       .setParam(PARAM_NAME, project.getName())
       .setParam(PARAM_BRANCH, project.getBranch());
index 94fc4c2b91e0c6a1a37cb2721c4c00dedbb038d0..1d3e3c5188194bcf9185c648d49002d36dc60015 100644 (file)
@@ -50,6 +50,22 @@ public class ProjectsServiceTest {
       entry("name", "Project Name"));
   }
 
+  @Test
+  public void creates_project_on_organization() {
+    underTest.create(CreateRequest.builder()
+      .setOrganization("org_key")
+      .setKey("project_key")
+      .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("organization", "org_key"),
+      entry("project", "project_key"),
+      entry("name", "Project Name"));
+  }
+
   @Test
   public void creates_project_on_branch() {
     underTest.create(CreateRequest.builder()