aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java4
-rw-r--r--server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java1
-rw-r--r--server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl13
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java8
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java19
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java6
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallDao.java11
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallMapper.java4
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmTesting.java29
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/alm/OrganizationAlmBindingDao.java76
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/alm/OrganizationAlmBindingDto.java125
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/alm/OrganizationAlmBindingMapper.java39
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/alm/ProjectAlmBindingDao.java (renamed from server/sonar-db-dao/src/main/java/org/sonar/db/alm/ProjectAlmBindingsDao.java)12
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/alm/ProjectAlmBindingMapper.java (renamed from server/sonar-db-dao/src/main/java/org/sonar/db/alm/ProjectAlmBindingsMapper.java)2
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/alm/AlmAppInstallMapper.xml12
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/alm/OrganizationAlmBindingMapper.xml67
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/alm/ProjectAlmBindingMapper.xml (renamed from server/sonar-db-dao/src/main/resources/org/sonar/db/alm/ProjectAlmBindingsMapper.xml)2
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java2
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/DbTester.java7
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/alm/AlmAppInstallDaoTest.java39
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/alm/AlmDbTester.java52
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/alm/OrganizationAlmBindingDaoTest.java158
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/alm/ProjectAlmBindingDaoTest.java (renamed from server/sonar-db-dao/src/test/java/org/sonar/db/alm/ProjectAlmBindingsDaoTest.java)4
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/CreateOrganizationsAlmBindingsTable.java112
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75.java1
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/CreateOrganizationsAlmBindingsTableTest.java67
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75Test.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationAlmBinding.java31
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationUpdater.java3
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationUpdaterImpl.java8
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/ws/CreateAction.java39
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsSupport.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/ws/SearchAction.java39
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/ui/ws/ComponentAction.java6
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/organization/OrganizationUpdaterImplTest.java41
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/organization/ws/CreateActionTest.java54
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/organization/ws/DeleteActionTest.java19
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/organization/ws/SearchActionTest.java23
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/ui/ws/ComponentActionTest.java46
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/ui/ws/ComponentActionTest/return_alm_infos_on_branch.json10
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/ui/ws/ComponentActionTest/return_alm_infos_on_module.json8
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/ui/ws/ComponentActionTest/return_alm_infos_on_project.json9
-rw-r--r--sonar-ws/src/main/protobuf/ws-organizations.proto6
44 files changed, 1101 insertions, 130 deletions
diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
index abc064e3142..c4e1ff35582 100644
--- a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
+++ b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
@@ -108,7 +108,7 @@ public class ComputeEngineContainerImplTest {
+ 3 // CeCleaningModule + its content
+ 4 // WebhookModule
+ 1 // CeDistributedInformation
- );
+ );
assertThat(picoContainer.getParent().getComponentAdapters()).hasSize(
CONTAINER_ITSELF
+ 8 // level 3
@@ -121,7 +121,7 @@ public class ComputeEngineContainerImplTest {
assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize(
COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION
+ 26 // level 1
- + 57 // content of DaoModule
+ + 58 // content of DaoModule
+ 3 // content of EsModule
+ 54 // content of CorePropertyDefinitions
+ 1 // StopFlagContainer
diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java b/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java
index 085d7de5625..0e699cba125 100644
--- a/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java
+++ b/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java
@@ -77,6 +77,7 @@ public final class SqTables {
"metrics",
"notifications",
"organizations",
+ "organization_alm_bindings",
"organization_members",
"org_qprofiles",
"org_quality_gates",
diff --git a/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl b/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl
index a1b83a1315d..cf18feb0316 100644
--- a/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl
+++ b/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl
@@ -902,3 +902,16 @@ CREATE TABLE "PROJECT_MAPPINGS" (
);
CREATE UNIQUE INDEX "KEY_TYPE_KEE" ON "PROJECT_MAPPINGS" ("KEY_TYPE", "KEE");
CREATE INDEX "PROJECT_UUID" ON "PROJECT_MAPPINGS" ("PROJECT_UUID");
+
+CREATE TABLE "ORGANIZATION_ALM_BINDINGS" (
+ "UUID" VARCHAR(40) NOT NULL,
+ "ORGANIZATION_UUID" VARCHAR(40) NOT NULL,
+ "ALM_APP_INSTALL_UUID" VARCHAR(40) NOT NULL,
+ "ALM_ID" VARCHAR(40) NOT NULL,
+ "URL" VARCHAR(2000) NOT NULL,
+ "USER_UUID" VARCHAR(255) NOT NULL,
+ "CREATED_AT" BIGINT NOT NULL,
+ CONSTRAINT "PK_ORGANIZATION_ALM_BINDINGS" PRIMARY KEY ("UUID")
+);
+CREATE UNIQUE INDEX "ORG_ALM_BINDINGS_ORG" ON "ORGANIZATION_ALM_BINDINGS" ("ORGANIZATION_UUID");
+CREATE UNIQUE INDEX "ORG_ALM_BINDINGS_INSTALL" ON "ORGANIZATION_ALM_BINDINGS" ("ALM_APP_INSTALL_UUID");
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java
index fbc228cdc35..bdc4097099a 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java
@@ -23,7 +23,9 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.sonar.core.platform.Module;
-import org.sonar.db.alm.ProjectAlmBindingsDao;
+import org.sonar.db.alm.AlmAppInstallDao;
+import org.sonar.db.alm.OrganizationAlmBindingDao;
+import org.sonar.db.alm.ProjectAlmBindingDao;
import org.sonar.db.ce.CeActivityDao;
import org.sonar.db.ce.CeQueueDao;
import org.sonar.db.ce.CeScannerContextDao;
@@ -41,7 +43,6 @@ import org.sonar.db.es.EsQueueDao;
import org.sonar.db.event.EventDao;
import org.sonar.db.issue.IssueChangeDao;
import org.sonar.db.issue.IssueDao;
-import org.sonar.db.alm.AlmAppInstallDao;
import org.sonar.db.mapping.ProjectMappingsDao;
import org.sonar.db.measure.LiveMeasureDao;
import org.sonar.db.measure.MeasureDao;
@@ -108,7 +109,7 @@ public class DaoModule extends Module {
GroupMembershipDao.class,
GroupPermissionDao.class,
AlmAppInstallDao.class,
- ProjectAlmBindingsDao.class,
+ ProjectAlmBindingDao.class,
InternalPropertiesDao.class,
IssueChangeDao.class,
IssueDao.class,
@@ -116,6 +117,7 @@ public class DaoModule extends Module {
MeasureDao.class,
MetricDao.class,
NotificationQueueDao.class,
+ OrganizationAlmBindingDao.class,
OrganizationDao.class,
OrganizationMemberDao.class,
PermissionTemplateCharacteristicDao.class,
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java
index edc6731c31b..8ba7cf8362f 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java
@@ -21,7 +21,9 @@ package org.sonar.db;
import java.util.IdentityHashMap;
import java.util.Map;
-import org.sonar.db.alm.ProjectAlmBindingsDao;
+import org.sonar.db.alm.AlmAppInstallDao;
+import org.sonar.db.alm.OrganizationAlmBindingDao;
+import org.sonar.db.alm.ProjectAlmBindingDao;
import org.sonar.db.ce.CeActivityDao;
import org.sonar.db.ce.CeQueueDao;
import org.sonar.db.ce.CeScannerContextDao;
@@ -39,7 +41,6 @@ import org.sonar.db.es.EsQueueDao;
import org.sonar.db.event.EventDao;
import org.sonar.db.issue.IssueChangeDao;
import org.sonar.db.issue.IssueDao;
-import org.sonar.db.alm.AlmAppInstallDao;
import org.sonar.db.mapping.ProjectMappingsDao;
import org.sonar.db.measure.LiveMeasureDao;
import org.sonar.db.measure.MeasureDao;
@@ -92,7 +93,7 @@ public class DbClient {
private final QualityProfileDao qualityProfileDao;
private final PropertiesDao propertiesDao;
private final AlmAppInstallDao almAppInstallDao;
- private final ProjectAlmBindingsDao projectAlmBindingsDao;
+ private final ProjectAlmBindingDao projectAlmBindingDao;
private final InternalPropertiesDao internalPropertiesDao;
private final SnapshotDao snapshotDao;
private final ComponentDao componentDao;
@@ -142,6 +143,7 @@ public class DbClient {
private final WebhookDao webhookDao;
private final WebhookDeliveryDao webhookDeliveryDao;
private final ProjectMappingsDao projectMappingsDao;
+ private final OrganizationAlmBindingDao organizationAlmBindingDao;
public DbClient(Database database, MyBatis myBatis, DBSessions dbSessions, Dao... daos) {
this.database = database;
@@ -153,7 +155,7 @@ public class DbClient {
map.put(dao.getClass(), dao);
}
almAppInstallDao = getDao(map, AlmAppInstallDao.class);
- projectAlmBindingsDao = getDao(map, ProjectAlmBindingsDao.class);
+ projectAlmBindingDao = getDao(map, ProjectAlmBindingDao.class);
schemaMigrationDao = getDao(map, SchemaMigrationDao.class);
authorizationDao = getDao(map, AuthorizationDao.class);
organizationDao = getDao(map, OrganizationDao.class);
@@ -209,6 +211,7 @@ public class DbClient {
webhookDao = getDao(map, WebhookDao.class);
webhookDeliveryDao = getDao(map, WebhookDeliveryDao.class);
projectMappingsDao = getDao(map, ProjectMappingsDao.class);
+ organizationAlmBindingDao = getDao(map, OrganizationAlmBindingDao.class);
}
public DbSession openSession(boolean batch) {
@@ -223,8 +226,8 @@ public class DbClient {
return almAppInstallDao;
}
- public ProjectAlmBindingsDao projectAlmBindingsDao() {
- return projectAlmBindingsDao;
+ public ProjectAlmBindingDao projectAlmBindingsDao() {
+ return projectAlmBindingDao;
}
public SchemaMigrationDao schemaMigrationDao() {
@@ -456,4 +459,8 @@ public class DbClient {
public ProjectMappingsDao projectMappingsDao() {
return projectMappingsDao;
}
+
+ public OrganizationAlmBindingDao organizationAlmBindingDao() {
+ return organizationAlmBindingDao;
+ }
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
index 93af5cc3914..846ca3724e2 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
@@ -31,8 +31,9 @@ import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.session.TransactionIsolationLevel;
import org.sonar.api.Startable;
import org.sonar.db.alm.AlmAppInstallMapper;
+import org.sonar.db.alm.OrganizationAlmBindingMapper;
import org.sonar.db.alm.ProjectAlmBindingDto;
-import org.sonar.db.alm.ProjectAlmBindingsMapper;
+import org.sonar.db.alm.ProjectAlmBindingMapper;
import org.sonar.db.ce.CeActivityMapper;
import org.sonar.db.ce.CeQueueMapper;
import org.sonar.db.ce.CeScannerContextMapper;
@@ -232,12 +233,13 @@ public class MyBatis implements Startable {
MeasureMapper.class,
MetricMapper.class,
NotificationQueueMapper.class,
+ OrganizationAlmBindingMapper.class,
OrganizationMapper.class,
OrganizationMemberMapper.class,
PermissionTemplateCharacteristicMapper.class,
PermissionTemplateMapper.class,
PluginMapper.class,
- ProjectAlmBindingsMapper.class,
+ ProjectAlmBindingMapper.class,
ProjectLinkMapper.class,
ProjectMappingsMapper.class,
ProjectQgateAssociationMapper.class,
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallDao.java
index 04302fe6f06..005017eefd8 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallDao.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallDao.java
@@ -29,6 +29,7 @@ import org.sonar.db.Dao;
import org.sonar.db.DbSession;
import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
import static org.apache.commons.lang.StringUtils.isNotEmpty;
/**
@@ -44,17 +45,17 @@ public class AlmAppInstallDao implements Dao {
this.uuidFactory = uuidFactory;
}
- public Optional<AlmAppInstallDto> selectByOwner(DbSession dbSession, ALM alm, String ownerId) {
+ public Optional<AlmAppInstallDto> selectByOwnerId(DbSession dbSession, ALM alm, String ownerId) {
checkAlm(alm);
checkOwnerId(ownerId);
AlmAppInstallMapper mapper = getMapper(dbSession);
- return Optional.ofNullable(mapper.selectByOwner(alm.getId(), ownerId));
+ return Optional.ofNullable(mapper.selectByOwnerId(alm.getId(), ownerId));
}
- public Optional<String> getOwerId(DbSession dbSession, ALM alm, String installationId) {
+ public Optional<AlmAppInstallDto> selectByInstallationId(DbSession dbSession, ALM alm, String installationId) {
AlmAppInstallMapper mapper = getMapper(dbSession);
- return Optional.ofNullable(mapper.selectOwnerId(alm.getId(), installationId));
+ return Optional.ofNullable(mapper.selectByInstallationId(alm.getId(), installationId));
}
public List<AlmAppInstallDto> findAllWithNoOwnerType(DbSession dbSession) {
@@ -88,7 +89,7 @@ public class AlmAppInstallDao implements Dao {
}
private static void checkAlm(@Nullable ALM alm) {
- Objects.requireNonNull(alm, "alm can't be null");
+ requireNonNull(alm, "alm can't be null");
}
private static void checkOwnerId(@Nullable String ownerId) {
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallMapper.java
index cb979c2217f..f840a5aa07b 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallMapper.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmAppInstallMapper.java
@@ -27,10 +27,10 @@ import org.apache.ibatis.annotations.Param;
public interface AlmAppInstallMapper {
@CheckForNull
- AlmAppInstallDto selectByOwner(@Param("almId") String almId, @Param("ownerId") String ownerId);
+ AlmAppInstallDto selectByOwnerId(@Param("almId") String almId, @Param("ownerId") String ownerId);
@CheckForNull
- String selectOwnerId(@Param("almId") String almId, @Param("installId") String installId);
+ AlmAppInstallDto selectByInstallationId(@Param("almId") String almId, @Param("installId") String installId);
List<AlmAppInstallDto> selectAllWithNoOwnerType();
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmTesting.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmTesting.java
new file mode 100644
index 00000000000..656be2fe655
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/AlmTesting.java
@@ -0,0 +1,29 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.db.alm;
+
+public class AlmTesting {
+
+ private AlmTesting() {
+ // only statics
+ }
+
+
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/OrganizationAlmBindingDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/OrganizationAlmBindingDao.java
new file mode 100644
index 00000000000..3612870461b
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/OrganizationAlmBindingDao.java
@@ -0,0 +1,76 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.db.alm;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.core.util.stream.MoreCollectors;
+import org.sonar.db.Dao;
+import org.sonar.db.DbSession;
+import org.sonar.db.organization.OrganizationDto;
+
+import static org.sonar.db.DatabaseUtils.executeLargeInputs;
+
+public class OrganizationAlmBindingDao implements Dao {
+
+ private final System2 system2;
+ private final UuidFactory uuidFactory;
+
+ public OrganizationAlmBindingDao(System2 system2, UuidFactory uuidFactory) {
+ this.system2 = system2;
+ this.uuidFactory = uuidFactory;
+ }
+
+ public Optional<OrganizationAlmBindingDto> selectByOrganization(DbSession dbSession, OrganizationDto organization) {
+ return Optional.ofNullable(getMapper(dbSession).selectByOrganizationUuid(organization.getUuid()));
+ }
+
+ public List<OrganizationAlmBindingDto> selectByOrganizations(DbSession dbSession, Collection<OrganizationDto> organizations) {
+ return executeLargeInputs(organizations.stream().map(OrganizationDto::getUuid).collect(MoreCollectors.toSet()),
+ organizationUuids -> getMapper(dbSession).selectByOrganizationUuids(organizationUuids));
+ }
+
+ public void insert(DbSession dbSession, OrganizationDto organization, AlmAppInstallDto almAppInstall, String url, String userUuid) {
+ long now = system2.now();
+ getMapper(dbSession).insert(new OrganizationAlmBindingDto()
+ .setUuid(uuidFactory.create())
+ .setOrganizationUuid(organization.getUuid())
+ .setAlmAppInstallUuid(almAppInstall.getUuid())
+ .setAlmId(almAppInstall.getAlm())
+ .setUrl(url)
+ .setUserUuid(userUuid)
+ .setCreatedAt(now));
+ }
+
+ public void deleteByOrganization(DbSession dbSession, OrganizationDto organization) {
+ getMapper(dbSession).deleteByOrganizationUuid(organization.getUuid());
+ }
+
+ public void deleteByAlmAppInstall(DbSession dbSession, AlmAppInstallDto almAppInstall) {
+ getMapper(dbSession).deleteByAlmAppInstallUuid(almAppInstall.getUuid());
+ }
+
+ private static OrganizationAlmBindingMapper getMapper(DbSession dbSession) {
+ return dbSession.getMapper(OrganizationAlmBindingMapper.class);
+ }
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/OrganizationAlmBindingDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/OrganizationAlmBindingDto.java
new file mode 100644
index 00000000000..30a2795a280
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/OrganizationAlmBindingDto.java
@@ -0,0 +1,125 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.db.alm;
+
+import java.util.Arrays;
+
+/**
+ * This DTO is used to link an {@link org.sonar.db.organization.OrganizationDto} to a {@link AlmAppInstallDto}
+ */
+public class OrganizationAlmBindingDto {
+
+ /**
+ * Not empty. Max size is 40. Obviously it is unique.
+ */
+ private String uuid;
+ /**
+ * The UUID of the organization. Can't be null. Max size is 40.
+ * It's unique, as an organization is only linked to one installation (at least for the moment).
+ */
+ private String organizationUuid;
+ /**
+ * The UUID of ALM installation. Can't be null. Max size is 40.
+ * It's unique, as an installation is related to only one organization.
+ */
+ private String almAppInstallUuid;
+ /**
+ * The id of the ALM. Can't be null. Max size is 40.
+ */
+ private String rawAlmId;
+ /**
+ * The url of the ALM organization. Can't be null. Max size is 2000.
+ */
+ private String url;
+ /**
+ * The UUID of the user who has created the link between the organization and the ALN installation. Can't be null. Max size is 255.
+ */
+ private String userUuid;
+ /**
+ * Technical creation date
+ */
+ private long createdAt;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ OrganizationAlmBindingDto setUuid(String uuid) {
+ this.uuid = uuid;
+ return this;
+ }
+
+ public String getOrganizationUuid() {
+ return organizationUuid;
+ }
+
+ public OrganizationAlmBindingDto setOrganizationUuid(String organizationUuid) {
+ this.organizationUuid = organizationUuid;
+ return this;
+ }
+
+ public String getAlmAppInstallUuid() {
+ return almAppInstallUuid;
+ }
+
+ public OrganizationAlmBindingDto setAlmAppInstallUuid(String almAppInstallUuid) {
+ this.almAppInstallUuid = almAppInstallUuid;
+ return this;
+ }
+
+ public ALM getAlm() {
+ return Arrays.stream(ALM.values())
+ .filter(a -> a.getId().equals(rawAlmId))
+ .findAny()
+ .orElseThrow(() -> new IllegalStateException("ALM id " + rawAlmId + " is invalid"));
+ }
+
+ public OrganizationAlmBindingDto setAlmId(ALM alm) {
+ this.rawAlmId = alm.getId();
+ return this;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public OrganizationAlmBindingDto setUrl(String url) {
+ this.url = url;
+ return this;
+ }
+
+ public String getUserUuid() {
+ return userUuid;
+ }
+
+ public OrganizationAlmBindingDto setUserUuid(String userUuid) {
+ this.userUuid = userUuid;
+ return this;
+ }
+
+ public long getCreatedAt() {
+ return createdAt;
+ }
+
+ OrganizationAlmBindingDto setCreatedAt(long createdAt) {
+ this.createdAt = createdAt;
+ return this;
+ }
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/OrganizationAlmBindingMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/OrganizationAlmBindingMapper.java
new file mode 100644
index 00000000000..f664a50f51b
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/OrganizationAlmBindingMapper.java
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.db.alm;
+
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import org.apache.ibatis.annotations.Param;
+
+public interface OrganizationAlmBindingMapper {
+
+ @CheckForNull
+ OrganizationAlmBindingDto selectByOrganizationUuid(@Param("organizationUuid") String organizationUuid);
+
+ List<OrganizationAlmBindingDto> selectByOrganizationUuids(@Param("organizationUuids") Collection<String> organizationUuids);
+
+ void insert(@Param("dto") OrganizationAlmBindingDto dto);
+
+ void deleteByOrganizationUuid(@Param("organizationUuid") String organizationUuid);
+
+ void deleteByAlmAppInstallUuid(@Param("almAppInstallUuid") String almAppInstallUuid);
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/ProjectAlmBindingsDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/ProjectAlmBindingDao.java
index 61b9bc5d56e..f2dc943914e 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/ProjectAlmBindingsDao.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/ProjectAlmBindingDao.java
@@ -33,12 +33,12 @@ import static com.google.common.base.Preconditions.checkArgument;
import static org.apache.commons.lang.StringUtils.isNotEmpty;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;
-public class ProjectAlmBindingsDao implements Dao {
+public class ProjectAlmBindingDao implements Dao {
private final System2 system2;
private final UuidFactory uuidFactory;
- public ProjectAlmBindingsDao(System2 system2, UuidFactory uuidFactory) {
+ public ProjectAlmBindingDao(System2 system2, UuidFactory uuidFactory) {
this.system2 = system2;
this.uuidFactory = uuidFactory;
}
@@ -49,7 +49,7 @@ public class ProjectAlmBindingsDao implements Dao {
checkArgument(isNotEmpty(projectUuid), "projectUuid can't be null nor empty");
checkArgument(isNotEmpty(url), "url can't be null nor empty");
- ProjectAlmBindingsMapper mapper = getMapper(dbSession);
+ ProjectAlmBindingMapper mapper = getMapper(dbSession);
long now = system2.now();
if (mapper.update(alm.getId(), repoId, projectUuid, githubSlug, url, now) == 0) {
@@ -78,7 +78,7 @@ public class ProjectAlmBindingsDao implements Dao {
checkAlm(alm);
checkRepoId(repoId);
- ProjectAlmBindingsMapper mapper = getMapper(dbSession);
+ ProjectAlmBindingMapper mapper = getMapper(dbSession);
return Optional.ofNullable(mapper.selectProjectKey(alm.getId(), repoId));
}
@@ -90,8 +90,8 @@ public class ProjectAlmBindingsDao implements Dao {
checkArgument(isNotEmpty(repoId), "repoId can't be null nor empty");
}
- private static ProjectAlmBindingsMapper getMapper(DbSession dbSession) {
- return dbSession.getMapper(ProjectAlmBindingsMapper.class);
+ private static ProjectAlmBindingMapper getMapper(DbSession dbSession) {
+ return dbSession.getMapper(ProjectAlmBindingMapper.class);
}
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/ProjectAlmBindingsMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/ProjectAlmBindingMapper.java
index df0484e5780..1849cf1c177 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/alm/ProjectAlmBindingsMapper.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/alm/ProjectAlmBindingMapper.java
@@ -24,7 +24,7 @@ import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.ibatis.annotations.Param;
-public interface ProjectAlmBindingsMapper {
+public interface ProjectAlmBindingMapper {
int bindingCount(@Param("almId") String almId, @Param("repoId") String repoId);
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/AlmAppInstallMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/AlmAppInstallMapper.xml
index d96a33dfe13..2fe08a4dd5e 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/AlmAppInstallMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/AlmAppInstallMapper.xml
@@ -13,7 +13,7 @@
updated_at as updatedAt
</sql>
- <select id="selectByOwner" parameterType="Map" resultType="org.sonar.db.alm.AlmAppInstallDto">
+ <select id="selectByOwnerId" parameterType="Map" resultType="org.sonar.db.alm.AlmAppInstallDto">
select <include refid="sqlColumns" />
from
alm_app_installs
@@ -22,14 +22,14 @@
and owner_id = #{ownerId, jdbcType=VARCHAR}
</select>
- <select id="selectOwnerId" parameterType="Map" resultType="String">
+ <select id="selectByInstallationId" parameterType="Map" resultType="org.sonar.db.alm.AlmAppInstallDto">
select
- owner_id as ownerId
+ <include refid="sqlColumns"/>
from
- alm_app_installs
+ alm_app_installs
where
- alm_id = #{almId, jdbcType=VARCHAR}
- and install_id = #{installId, jdbcType=VARCHAR}
+ alm_id = #{almId, jdbcType=VARCHAR}
+ and install_id = #{installId, jdbcType=VARCHAR}
</select>
<select id="selectAllWithNoOwnerType" parameterType="Map" resultType="org.sonar.db.alm.AlmAppInstallDto">
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/OrganizationAlmBindingMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/OrganizationAlmBindingMapper.xml
new file mode 100644
index 00000000000..395eb9100e5
--- /dev/null
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/OrganizationAlmBindingMapper.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd">
+
+<mapper namespace="org.sonar.db.alm.OrganizationAlmBindingMapper">
+
+ <sql id="columns">
+ uuid,
+ organization_uuid as organizationUuid,
+ alm_app_install_uuid as almAppInstallUuid,
+ alm_id as rawAlmId,
+ url,
+ user_uuid as userUuid,
+ created_at as createdAt
+ </sql>
+
+ <select id="selectByOrganizationUuid" parameterType="String" resultType="org.sonar.db.alm.OrganizationAlmBindingDto">
+ select
+ <include refid="columns"/>
+ from
+ organization_alm_bindings
+ where
+ organization_uuid = #{organizationUuid, jdbcType=VARCHAR}
+ </select>
+
+ <select id="selectByOrganizationUuids" parameterType="String" resultType="org.sonar.db.alm.OrganizationAlmBindingDto">
+ select
+ <include refid="columns"/>
+ from
+ organization_alm_bindings
+ where
+ organization_uuid in
+ <foreach collection="organizationUuids" open="(" close=")" item="organizationUuid" separator=",">
+ #{organizationUuid , jdbcType=VARCHAR}
+ </foreach>
+ </select>
+
+ <insert id="insert" parameterType="Map" useGeneratedKeys="false">
+ INSERT INTO organization_alm_bindings
+ (
+ uuid,
+ organization_uuid,
+ alm_app_install_uuid,
+ alm_id,
+ url,
+ user_uuid,
+ created_at
+ )
+ VALUES (
+ #{dto.uuid, jdbcType=VARCHAR},
+ #{dto.organizationUuid, jdbcType=VARCHAR},
+ #{dto.almAppInstallUuid, jdbcType=VARCHAR},
+ #{dto.rawAlmId, jdbcType=VARCHAR},
+ #{dto.url, jdbcType=VARCHAR},
+ #{dto.userUuid, jdbcType=VARCHAR},
+ #{dto.createdAt, jdbcType=BIGINT}
+ )
+ </insert>
+
+ <delete id="deleteByOrganizationUuid" parameterType="String">
+ DELETE FROM organization_alm_bindings WHERE organization_uuid = #{organizationUuid, jdbcType=VARCHAR}
+ </delete>
+
+ <delete id="deleteByAlmAppInstallUuid" parameterType="String">
+ DELETE FROM organization_alm_bindings WHERE alm_app_install_uuid = #{almAppInstallUuid, jdbcType=VARCHAR}
+ </delete>
+
+</mapper>
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/ProjectAlmBindingsMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/ProjectAlmBindingMapper.xml
index 27f5d1f720a..845af9e7d2e 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/ProjectAlmBindingsMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/alm/ProjectAlmBindingMapper.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd">
-<mapper namespace="org.sonar.db.alm.ProjectAlmBindingsMapper">
+<mapper namespace="org.sonar.db.alm.ProjectAlmBindingMapper">
<sql id="columns">
uuid,
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java
index 307a4db0861..116af4636e4 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java
@@ -30,6 +30,6 @@ public class DaoModuleTest {
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new DaoModule().configure(container);
- assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 57);
+ assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 58);
}
}
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/DbTester.java b/server/sonar-db-dao/src/test/java/org/sonar/db/DbTester.java
index 15f11f5d2d0..82194a971a4 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/DbTester.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/DbTester.java
@@ -29,6 +29,7 @@ import org.apache.commons.lang.StringUtils;
import org.picocontainer.containers.TransientPicoContainer;
import org.sonar.api.utils.System2;
import org.sonar.core.util.SequenceUuidFactory;
+import org.sonar.db.alm.AlmDbTester;
import org.sonar.db.component.ComponentDbTester;
import org.sonar.db.component.ProjectLinkDbTester;
import org.sonar.db.event.EventDbTester;
@@ -87,6 +88,7 @@ public class DbTester extends AbstractDbTester<TestDb> {
private final PluginDbTester pluginDbTester;
private final WebhookDbTester webhookDbTester;
private final WebhookDeliveryDbTester webhookDeliveryDbTester;
+ private final AlmDbTester almDbTester;
public DbTester(System2 system2, @Nullable String schemaPath) {
super(TestDb.create(schemaPath));
@@ -112,6 +114,7 @@ public class DbTester extends AbstractDbTester<TestDb> {
this.pluginDbTester = new PluginDbTester(this);
this.webhookDbTester = new WebhookDbTester(this);
this.webhookDeliveryDbTester = new WebhookDeliveryDbTester(this);
+ this.almDbTester = new AlmDbTester(this);
}
public static DbTester create() {
@@ -262,6 +265,10 @@ public class DbTester extends AbstractDbTester<TestDb> {
return webhookDeliveryDbTester;
}
+ public AlmDbTester alm() {
+ return almDbTester;
+ }
+
@Override
protected void after() {
if (session != null) {
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/alm/AlmAppInstallDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/AlmAppInstallDaoTest.java
index 00955915f03..ddc76bdf316 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/alm/AlmAppInstallDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/AlmAppInstallDaoTest.java
@@ -60,47 +60,54 @@ public class AlmAppInstallDaoTest {
private AlmAppInstallDao underTest = new AlmAppInstallDao(system2, uuidFactory);
@Test
- public void selectByOwner() {
+ public void selectByOwnerId() {
when(uuidFactory.create()).thenReturn(A_UUID);
when(system2.now()).thenReturn(DATE);
underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, true, AN_INSTALL);
- assertThat(underTest.selectByOwner(dbSession, GITHUB, A_OWNER).get())
- .extracting(AlmAppInstallDto::getUuid, AlmAppInstallDto::getInstallId, AlmAppInstallDto::getOwnerId, AlmAppInstallDto::getAlm, AlmAppInstallDto::getCreatedAt, AlmAppInstallDto::getUpdatedAt)
- .containsExactlyInAnyOrder(A_UUID, AN_INSTALL, A_OWNER, ALM.GITHUB, DATE, DATE);
- assertThat(underTest.selectByOwner(dbSession, GITHUB, "unknown")).isEmpty();
- assertThat(underTest.selectByOwner(dbSession, BITBUCKETCLOUD, A_OWNER)).isEmpty();
+ assertThat(underTest.selectByOwnerId(dbSession, GITHUB, A_OWNER).get())
+ .extracting(AlmAppInstallDto::getUuid, AlmAppInstallDto::getAlm, AlmAppInstallDto::getInstallId, AlmAppInstallDto::getOwnerId,
+ AlmAppInstallDto::getCreatedAt, AlmAppInstallDto::getUpdatedAt)
+ .contains(A_UUID, GITHUB, A_OWNER, AN_INSTALL, DATE, DATE);
+
+ assertThat(underTest.selectByOwnerId(dbSession, BITBUCKETCLOUD, A_OWNER)).isNotPresent();
+ assertThat(underTest.selectByOwnerId(dbSession, GITHUB, "Unknown owner")).isNotPresent();
}
@Test
public void selectByOwner_throws_NPE_when_alm_is_null() {
expectAlmNPE();
- underTest.selectByOwner(dbSession, null, A_OWNER);
+ underTest.selectByOwnerId(dbSession, null, A_OWNER);
}
@Test
public void selectByOwner_throws_IAE_when_owner_id_is_null() {
expectOwnerIdNullOrEmptyIAE();
- underTest.selectByOwner(dbSession, GITHUB, null);
+ underTest.selectByOwnerId(dbSession, GITHUB, null);
}
@Test
public void selectByOwner_throws_IAE_when_owner_id_is_empty() {
expectOwnerIdNullOrEmptyIAE();
- underTest.selectByOwner(dbSession, GITHUB, EMPTY_STRING);
+ underTest.selectByOwnerId(dbSession, GITHUB, EMPTY_STRING);
}
@Test
- public void getOwnerId() {
+ public void selectByInstallationId() {
when(uuidFactory.create()).thenReturn(A_UUID);
+ when(system2.now()).thenReturn(DATE);
underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, true, AN_INSTALL);
- assertThat(underTest.getOwerId(dbSession, GITHUB, AN_INSTALL)).contains(A_OWNER);
- assertThat(underTest.getOwerId(dbSession, GITHUB, "unknown")).isEmpty();
- assertThat(underTest.getOwerId(dbSession, BITBUCKETCLOUD, AN_INSTALL)).isEmpty();
+ assertThat(underTest.selectByInstallationId(dbSession, GITHUB, AN_INSTALL).get())
+ .extracting(AlmAppInstallDto::getUuid, AlmAppInstallDto::getAlm, AlmAppInstallDto::getInstallId, AlmAppInstallDto::getOwnerId,
+ AlmAppInstallDto::getCreatedAt, AlmAppInstallDto::getUpdatedAt)
+ .contains(A_UUID, GITHUB, A_OWNER, AN_INSTALL, DATE, DATE);
+
+ assertThat(underTest.selectByInstallationId(dbSession, GITHUB, "unknown installation")).isEmpty();
+ assertThat(underTest.selectByInstallationId(dbSession, BITBUCKETCLOUD, AN_INSTALL)).isEmpty();
}
@Test
@@ -166,7 +173,7 @@ public class AlmAppInstallDaoTest {
}
@Test
- public void delete_doesn_t_fail() {
+ public void delete_does_not_fail() {
assertThatAlmAppInstall(GITHUB, A_OWNER).doesNotExist();
underTest.delete(dbSession, GITHUB, A_OWNER);
@@ -179,7 +186,7 @@ public class AlmAppInstallDaoTest {
underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, true, AN_INSTALL);
when(system2.now()).thenReturn(DATE_LATER);
- underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER,true, OTHER_INSTALL);
+ underTest.insertOrUpdate(dbSession, GITHUB, A_OWNER, true, OTHER_INSTALL);
assertThatAlmAppInstall(GITHUB, A_OWNER)
.hasInstallId(OTHER_INSTALL)
@@ -235,7 +242,7 @@ public class AlmAppInstallDaoTest {
}
private static AlmAppInstallDto asAlmAppInstall(DbTester db, DbSession dbSession, ALM alm, String ownerId) {
- Optional<AlmAppInstallDto> almAppInstall = db.getDbClient().almAppInstallDao().selectByOwner(dbSession, alm, ownerId);
+ Optional<AlmAppInstallDto> almAppInstall = db.getDbClient().almAppInstallDao().selectByOwnerId(dbSession, alm, ownerId);
return almAppInstall.orElse(null);
}
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/alm/AlmDbTester.java b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/AlmDbTester.java
new file mode 100644
index 00000000000..f129b5923ae
--- /dev/null
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/AlmDbTester.java
@@ -0,0 +1,52 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.db.alm;
+
+import org.sonar.db.DbTester;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.user.UserDto;
+
+import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+import static org.sonar.db.alm.ALM.GITHUB;
+
+public class AlmDbTester {
+
+ private final DbTester db;
+
+ public AlmDbTester(DbTester db) {
+ this.db = db;
+ }
+
+ public OrganizationAlmBindingDto insertOrganizationAlmBinding(OrganizationDto organization, AlmAppInstallDto almAppInstall) {
+ UserDto user = db.users().insertUser();
+ db.getDbClient().organizationAlmBindingDao().insert(db.getSession(), organization, almAppInstall, randomAlphabetic(10), user.getUuid());
+ return db.getDbClient().organizationAlmBindingDao().selectByOrganization(db.getSession(), organization).get();
+ }
+
+ public AlmAppInstallDto insertAlmAppInstall() {
+ ALM alm = GITHUB;
+ String ownerId = randomAlphanumeric(10);
+ db.getDbClient().almAppInstallDao().insertOrUpdate(db.getSession(), alm, ownerId, false, randomAlphanumeric(10));
+ return db.getDbClient().almAppInstallDao().selectByOwnerId(db.getSession(), alm, ownerId).get();
+ }
+
+}
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/alm/OrganizationAlmBindingDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/OrganizationAlmBindingDaoTest.java
new file mode 100644
index 00000000000..8972e200a09
--- /dev/null
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/OrganizationAlmBindingDaoTest.java
@@ -0,0 +1,158 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.db.alm;
+
+import java.util.Optional;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.core.util.Uuids;
+import org.sonar.db.DbTester;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.user.UserDto;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+import static org.assertj.core.groups.Tuple.tuple;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class OrganizationAlmBindingDaoTest {
+
+ private static final long NOW = 1_600_000_000_000L;
+
+ private System2 system2 = new TestSystem2().setNow(NOW);
+
+ @Rule
+ public DbTester db = DbTester.create(system2);
+
+ private UuidFactory uuidFactory = mock(UuidFactory.class);
+
+ private OrganizationAlmBindingDao underTest = new OrganizationAlmBindingDao(system2, uuidFactory);
+
+ @Test
+ public void selectByOrganization() {
+ OrganizationDto organization = db.organizations().insert();
+ AlmAppInstallDto almAppInstall = db.alm().insertAlmAppInstall();
+ OrganizationAlmBindingDto dto = db.alm().insertOrganizationAlmBinding(organization, almAppInstall);
+
+ Optional<OrganizationAlmBindingDto> result = underTest.selectByOrganization(db.getSession(), organization);
+
+ assertThat(result).isPresent();
+ assertThat(result.get())
+ .extracting(OrganizationAlmBindingDto::getUuid, OrganizationAlmBindingDto::getOrganizationUuid, OrganizationAlmBindingDto::getAlmAppInstallUuid,
+ OrganizationAlmBindingDto::getUrl, OrganizationAlmBindingDto::getAlm,
+ OrganizationAlmBindingDto::getUserUuid, OrganizationAlmBindingDto::getCreatedAt)
+ .containsExactlyInAnyOrder(dto.getUuid(), organization.getUuid(), dto.getAlmAppInstallUuid(),
+ dto.getUrl(), ALM.GITHUB,
+ dto.getUserUuid(), NOW);
+ }
+
+ @Test
+ public void selectByOrganization_returns_empty_when_organization_is_not_bound_to_installation() {
+ OrganizationDto organization = db.organizations().insert();
+ AlmAppInstallDto almAppInstall = db.alm().insertAlmAppInstall();
+ db.alm().insertOrganizationAlmBinding(organization, almAppInstall);
+ // No binding on other organization
+ OrganizationDto otherOrganization = db.organizations().insert();
+
+ Optional<OrganizationAlmBindingDto> result = underTest.selectByOrganization(db.getSession(), otherOrganization);
+
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void selectByOrganizations() {
+ OrganizationDto organization1 = db.organizations().insert();
+ OrganizationAlmBindingDto organizationAlmBinding1 = db.alm().insertOrganizationAlmBinding(organization1, db.alm().insertAlmAppInstall());
+ OrganizationDto organization2 = db.organizations().insert();
+ OrganizationAlmBindingDto organizationAlmBinding2 = db.alm().insertOrganizationAlmBinding(organization2, db.alm().insertAlmAppInstall());
+ OrganizationDto organizationNotBound = db.organizations().insert();
+
+ assertThat(underTest.selectByOrganizations(db.getSession(), asList(organization1, organization2, organizationNotBound)))
+ .extracting(OrganizationAlmBindingDto::getUuid, OrganizationAlmBindingDto::getOrganizationUuid)
+ .containsExactlyInAnyOrder(
+ tuple(organizationAlmBinding1.getUuid(), organization1.getUuid()),
+ tuple(organizationAlmBinding2.getUuid(), organization2.getUuid()));
+
+ assertThat(underTest.selectByOrganizations(db.getSession(), singletonList(organizationNotBound))).isEmpty();
+ }
+
+ @Test
+ public void insert() {
+ when(uuidFactory.create()).thenReturn("ABCD");
+ OrganizationDto organization = db.organizations().insert();
+ UserDto user = db.users().insertUser();
+ AlmAppInstallDto almAppInstall = db.alm().insertAlmAppInstall();
+
+ underTest.insert(db.getSession(), organization, almAppInstall, "http://myorg.com", user.getUuid());
+
+ assertThat(db.selectFirst(db.getSession(),
+ "select" +
+ " uuid as \"uuid\", organization_uuid as \"organizationUuid\", alm_app_install_uuid as \"almAppInstallUuid\", url as \"url\", alm_id as \"almId\"," +
+ " user_uuid as \"userUuid\", created_at as \"createdAt\"" +
+ " from organization_alm_bindings" +
+ " where organization_uuid='" + organization.getUuid() + "'"))
+ .contains(
+ entry("uuid", "ABCD"),
+ entry("organizationUuid", organization.getUuid()),
+ entry("almAppInstallUuid", almAppInstall.getUuid()),
+ entry("almId", "github"),
+ entry("url", "http://myorg.com"),
+ entry("userUuid", user.getUuid()),
+ entry("createdAt", NOW));
+ }
+
+ @Test
+ public void deleteByOrganization() {
+ OrganizationDto organization = db.organizations().insert();
+ AlmAppInstallDto almAppInstall = db.alm().insertAlmAppInstall();
+ db.alm().insertOrganizationAlmBinding(organization, almAppInstall);
+ OrganizationDto otherOrganization = db.organizations().insert();
+ AlmAppInstallDto otherAlmAppInstall = db.alm().insertAlmAppInstall();
+ db.alm().insertOrganizationAlmBinding(otherOrganization, otherAlmAppInstall);
+
+ underTest.deleteByOrganization(db.getSession(), organization);
+
+ assertThat(underTest.selectByOrganization(db.getSession(), organization)).isNotPresent();
+ assertThat(underTest.selectByOrganization(db.getSession(), otherOrganization)).isPresent();
+ }
+
+ @Test
+ public void deleteByAlmAppInstall() {
+ OrganizationDto organization = db.organizations().insert();
+ AlmAppInstallDto almAppInstall = db.alm().insertAlmAppInstall();
+ db.alm().insertOrganizationAlmBinding(organization, almAppInstall);
+ OrganizationDto otherOrganization = db.organizations().insert();
+ AlmAppInstallDto otherAlmAppInstall = db.alm().insertAlmAppInstall();
+ db.alm().insertOrganizationAlmBinding(otherOrganization, otherAlmAppInstall);
+
+ underTest.deleteByAlmAppInstall(db.getSession(), almAppInstall);
+
+ assertThat(underTest.selectByOrganization(db.getSession(), organization)).isNotPresent();
+ assertThat(underTest.selectByOrganization(db.getSession(), otherOrganization)).isPresent();
+ }
+
+}
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/alm/ProjectAlmBindingsDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/ProjectAlmBindingDaoTest.java
index 0db93b0bac7..2dd6635c427 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/alm/ProjectAlmBindingsDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/alm/ProjectAlmBindingDaoTest.java
@@ -45,7 +45,7 @@ import static org.mockito.Mockito.when;
import static org.sonar.db.alm.ALM.BITBUCKETCLOUD;
import static org.sonar.db.alm.ALM.GITHUB;
-public class ProjectAlmBindingsDaoTest {
+public class ProjectAlmBindingDaoTest {
private static final String A_UUID = "abcde1234";
private static final String ANOTHER_UUID = "xyz789";
@@ -73,7 +73,7 @@ public class ProjectAlmBindingsDaoTest {
private DbSession dbSession = dbTester.getSession();
private UuidFactory uuidFactory = mock(UuidFactory.class);
- private ProjectAlmBindingsDao underTest = new ProjectAlmBindingsDao(system2, uuidFactory);
+ private ProjectAlmBindingDao underTest = new ProjectAlmBindingDao(system2, uuidFactory);
@Test
public void insert_throws_NPE_if_alm_is_null() {
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/CreateOrganizationsAlmBindingsTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/CreateOrganizationsAlmBindingsTable.java
new file mode 100644
index 00000000000..676455672a8
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/CreateOrganizationsAlmBindingsTable.java
@@ -0,0 +1,112 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.platform.db.migration.version.v75;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.db.DatabaseUtils;
+import org.sonar.server.platform.db.migration.def.BigIntegerColumnDef;
+import org.sonar.server.platform.db.migration.def.VarcharColumnDef;
+import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder;
+import org.sonar.server.platform.db.migration.sql.CreateTableBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.BigIntegerColumnDef.newBigIntegerColumnDefBuilder;
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder;
+
+public class CreateOrganizationsAlmBindingsTable extends DdlChange {
+
+ private static final String TABLE_NAME = "organization_alm_bindings";
+
+ private static final VarcharColumnDef UUID_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("uuid")
+ .setIsNullable(false)
+ .setLimit(VarcharColumnDef.UUID_SIZE)
+ .build();
+ private static final VarcharColumnDef ORGANIZATION_UUID_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("organization_uuid")
+ .setIsNullable(false)
+ .setLimit(VarcharColumnDef.UUID_SIZE)
+ .build();
+ private static final VarcharColumnDef ALM_APP_INSTALL_UUID_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("alm_app_install_uuid")
+ .setIsNullable(false)
+ .setLimit(VarcharColumnDef.UUID_SIZE)
+ .build();
+ private static final VarcharColumnDef ALM_ID_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("alm_id")
+ .setIsNullable(false)
+ .setLimit(40)
+ .build();
+ private static final VarcharColumnDef URL_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("url")
+ .setIsNullable(false)
+ .setLimit(2000)
+ .build();
+ private static final VarcharColumnDef USER_UUID_COLUMN = newVarcharColumnDefBuilder()
+ .setColumnName("user_uuid")
+ .setIsNullable(false)
+ .setLimit(255)
+ .build();
+ private static final BigIntegerColumnDef CREATED_AT_COLUMN = newBigIntegerColumnDefBuilder()
+ .setColumnName("created_at")
+ .setIsNullable(false)
+ .build();
+
+ public CreateOrganizationsAlmBindingsTable(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ if (!tableExists()) {
+ context.execute(new CreateTableBuilder(getDialect(), TABLE_NAME)
+ .addPkColumn(UUID_COLUMN)
+ .addColumn(ORGANIZATION_UUID_COLUMN)
+ .addColumn(ALM_APP_INSTALL_UUID_COLUMN)
+ .addColumn(ALM_ID_COLUMN)
+ .addColumn(URL_COLUMN)
+ .addColumn(USER_UUID_COLUMN)
+ .addColumn(CREATED_AT_COLUMN)
+ .build());
+
+ context.execute(new CreateIndexBuilder(getDialect())
+ .addColumn(ORGANIZATION_UUID_COLUMN)
+ .setUnique(true)
+ .setTable(TABLE_NAME)
+ .setName("org_alm_bindings_org")
+ .build());
+
+ context.execute(new CreateIndexBuilder(getDialect())
+ .addColumn(ALM_APP_INSTALL_UUID_COLUMN)
+ .setUnique(true)
+ .setTable(TABLE_NAME)
+ .setName("org_alm_bindings_install")
+ .build());
+ }
+ }
+
+ private boolean tableExists() throws SQLException {
+ try (Connection connection = getDatabase().getDataSource().getConnection()) {
+ return DatabaseUtils.tableExists(TABLE_NAME, connection);
+ }
+ }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75.java
index ec7c0d05c35..65c33aa424e 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75.java
@@ -28,6 +28,7 @@ public class DbVersion75 implements DbVersion {
public void addSteps(MigrationStepRegistry registry) {
registry
.add(2400, "Add column IS_OWNER_USER in ALM_APP_INSTALLS", AddIsOwnerUserColumnInAlmAppInstall.class)
+ .add(2401, "Create ORGANIZATION_ALM_BINDINGS table", CreateOrganizationsAlmBindingsTable.class)
;
}
}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/CreateOrganizationsAlmBindingsTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/CreateOrganizationsAlmBindingsTableTest.java
new file mode 100644
index 00000000000..7cac352e8f6
--- /dev/null
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/CreateOrganizationsAlmBindingsTableTest.java
@@ -0,0 +1,67 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.platform.db.migration.version.v75;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+import static java.sql.Types.VARCHAR;
+
+public class CreateOrganizationsAlmBindingsTableTest {
+
+ private static final String TABLE = "organization_alm_bindings";
+
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createEmpty();
+
+ private CreateOrganizationsAlmBindingsTable underTest = new CreateOrganizationsAlmBindingsTable(db.database());
+
+ @Test
+ public void creates_table() throws SQLException {
+ underTest.execute();
+
+ checkTable();
+ }
+
+ @Test
+ public void migration_is_reentrant() throws SQLException {
+ underTest.execute();
+ underTest.execute();
+
+ checkTable();
+ }
+
+ private void checkTable() {
+ db.assertColumnDefinition(TABLE, "uuid", Types.VARCHAR, 40, false);
+ db.assertColumnDefinition(TABLE, "organization_uuid", VARCHAR, 40, false);
+ db.assertColumnDefinition(TABLE, "alm_app_install_uuid", VARCHAR, 40, false);
+ db.assertColumnDefinition(TABLE, "alm_id", Types.VARCHAR, 40, false);
+ db.assertColumnDefinition(TABLE, "url", Types.VARCHAR, 2000, false);
+ db.assertColumnDefinition(TABLE, "user_uuid", Types.VARCHAR, 255, false);
+ db.assertColumnDefinition(TABLE, "created_at", Types.BIGINT, null, false);
+
+ db.assertUniqueIndex(TABLE, "org_alm_bindings_org", "organization_uuid");
+ db.assertUniqueIndex(TABLE, "org_alm_bindings_install", "alm_app_install_uuid");
+ }
+
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75Test.java
index c6d922ba3b0..0b940dbcb16 100644
--- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75Test.java
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v75/DbVersion75Test.java
@@ -35,6 +35,6 @@ public class DbVersion75Test {
@Test
public void verify_migration_count() {
- verifyMigrationCount(underTest, 1);
+ verifyMigrationCount(underTest, 2);
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationAlmBinding.java b/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationAlmBinding.java
new file mode 100644
index 00000000000..7fccdc922b5
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationAlmBinding.java
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.organization;
+
+import org.sonar.api.server.ServerSide;
+import org.sonar.db.DbSession;
+import org.sonar.db.organization.OrganizationDto;
+
+@ServerSide
+public interface OrganizationAlmBinding {
+
+ void bindOrganization(DbSession dbSession, OrganizationDto organization, String installationId);
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationUpdater.java
index 60bb5006439..6bb14d6fb72 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationUpdater.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationUpdater.java
@@ -20,6 +20,7 @@
package org.sonar.server.organization;
import java.util.Optional;
+import java.util.function.Consumer;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.web.UserRole;
@@ -72,7 +73,7 @@ public interface OrganizationUpdater {
* @throws KeyConflictException if an organization with the specified key already exists
* @throws IllegalArgumentException if any field of {@code newOrganization} is invalid according to {@link OrganizationValidation}
*/
- OrganizationDto create(DbSession dbSession, UserDto userCreator, NewOrganization newOrganization) throws KeyConflictException;
+ OrganizationDto create(DbSession dbSession, UserDto userCreator, NewOrganization newOrganization, Consumer<OrganizationDto> beforeCommit) throws KeyConflictException;
/**
* Create a new guarded organization which details are based on the login of the specified User.
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationUpdaterImpl.java b/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationUpdaterImpl.java
index cc6b889a0c8..5765db7c88c 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationUpdaterImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationUpdaterImpl.java
@@ -94,7 +94,7 @@ public class OrganizationUpdaterImpl implements OrganizationUpdater {
}
@Override
- public OrganizationDto create(DbSession dbSession, UserDto userCreator, NewOrganization newOrganization) throws KeyConflictException {
+ public OrganizationDto create(DbSession dbSession, UserDto userCreator, NewOrganization newOrganization, Consumer<OrganizationDto> beforeCommit) throws KeyConflictException {
validate(newOrganization);
String key = newOrganization.getKey();
if (organizationKeyIsUsed(dbSession, key)) {
@@ -103,16 +103,16 @@ public class OrganizationUpdaterImpl implements OrganizationUpdater {
QualityGateDto builtInQualityGate = dbClient.qualityGateDao().selectBuiltIn(dbSession);
OrganizationDto organization = insertOrganization(dbSession, newOrganization, builtInQualityGate);
+ beforeCommit.accept(organization);
insertOrganizationMember(dbSession, organization, userCreator.getId());
dbClient.qualityGateDao().associate(dbSession, uuidFactory.create(), organization, builtInQualityGate);
GroupDto ownerGroup = insertOwnersGroup(dbSession, organization);
GroupDto defaultGroup = defaultGroupCreator.create(dbSession, organization.getUuid());
insertDefaultTemplateOnGroups(dbSession, organization, ownerGroup, defaultGroup);
+ addCurrentUserToGroup(dbSession, ownerGroup, userCreator.getId());
+ addCurrentUserToGroup(dbSession, defaultGroup, userCreator.getId());
try (DbSession batchDbSession = dbClient.openSession(true)) {
insertQualityProfiles(dbSession, batchDbSession, organization);
- addCurrentUserToGroup(dbSession, ownerGroup, userCreator.getId());
- addCurrentUserToGroup(dbSession, defaultGroup, userCreator.getId());
-
batchDbSession.commit();
// Elasticsearch is updated when DB session is committed
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/CreateAction.java b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/CreateAction.java
index 136866aff69..992add61372 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/CreateAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/CreateAction.java
@@ -31,6 +31,7 @@ import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.user.UserDto;
+import org.sonar.server.organization.OrganizationAlmBinding;
import org.sonar.server.organization.OrganizationFlags;
import org.sonar.server.organization.OrganizationUpdater;
import org.sonar.server.organization.OrganizationValidation;
@@ -38,6 +39,7 @@ import org.sonar.server.user.UserSession;
import org.sonarqube.ws.Organizations.CreateWsResponse;
import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
import static org.sonar.server.organization.OrganizationUpdater.NewOrganization.newOrganizationBuilder;
import static org.sonar.server.organization.OrganizationValidation.KEY_MAX_LENGTH;
import static org.sonar.server.organization.OrganizationValidation.KEY_MIN_LENGTH;
@@ -45,7 +47,9 @@ import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_KEY;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
public class CreateAction implements OrganizationsWsAction {
+
private static final String ACTION = "create";
+ private static final String PARAM_INSTALLATION_ID = "installationId";
private final Configuration config;
private final UserSession userSession;
@@ -54,9 +58,12 @@ public class CreateAction implements OrganizationsWsAction {
private final OrganizationValidation organizationValidation;
private final OrganizationUpdater organizationUpdater;
private final OrganizationFlags organizationFlags;
+ @CheckForNull
+ private final OrganizationAlmBinding organizationAlmBinding;
public CreateAction(Configuration config, UserSession userSession, DbClient dbClient, OrganizationsWsSupport wsSupport,
- OrganizationValidation organizationValidation, OrganizationUpdater organizationUpdater, OrganizationFlags organizationFlags) {
+ OrganizationValidation organizationValidation, OrganizationUpdater organizationUpdater, OrganizationFlags organizationFlags,
+ @Nullable OrganizationAlmBinding organizationAlmBinding) {
this.config = config;
this.userSession = userSession;
this.dbClient = dbClient;
@@ -64,6 +71,12 @@ public class CreateAction implements OrganizationsWsAction {
this.organizationValidation = organizationValidation;
this.organizationUpdater = organizationUpdater;
this.organizationFlags = organizationFlags;
+ this.organizationAlmBinding = organizationAlmBinding;
+ }
+
+ public CreateAction(Configuration config, UserSession userSession, DbClient dbClient, OrganizationsWsSupport wsSupport,
+ OrganizationValidation organizationValidation, OrganizationUpdater organizationUpdater, OrganizationFlags organizationFlags) {
+ this(config, userSession, dbClient, wsSupport, organizationValidation, organizationUpdater, organizationFlags, null);
}
@Override
@@ -77,8 +90,7 @@ public class CreateAction implements OrganizationsWsAction {
.setSince("6.2")
.setChangelog(
new Change("7.4", "Maximal number of character of name and key is 300 characters"),
- new Change("7.2", "Minimal number of character of name and key is one character")
- )
+ new Change("7.2", "Minimal number of character of name and key is one character"))
.setHandler(this);
action.createParam(PARAM_KEY)
@@ -90,6 +102,11 @@ public class CreateAction implements OrganizationsWsAction {
"When not specified, the key is computed from the name. <br />" +
"All chars must be lower-case letters (a to z), digits or dash (but dash can neither be trailing nor heading)")
.setExampleValue("foo-company");
+ action.createParam(PARAM_INSTALLATION_ID)
+ .setRequired(false)
+ .setInternal(true)
+ .setDescription("Installation ID of the GitHub/Bitbucket application")
+ .setExampleValue("387133");
wsSupport.addOrganizationDetailsParams(action, true);
}
@@ -111,7 +128,7 @@ public class CreateAction implements OrganizationsWsAction {
try (DbSession dbSession = dbClient.openSession(false)) {
organizationFlags.checkEnabled(dbSession);
- UserDto currentUser = dbClient.userDao().selectActiveUserByLogin(dbSession, userSession.getLogin());
+ UserDto currentUser = requireNonNull(dbClient.userDao().selectActiveUserByLogin(dbSession, requireNonNull(userSession.getLogin())));
OrganizationDto organization = organizationUpdater.create(
dbSession,
currentUser,
@@ -121,7 +138,8 @@ public class CreateAction implements OrganizationsWsAction {
.setDescription(description)
.setUrl(url)
.setAvatarUrl(avatar)
- .build());
+ .build(),
+ o -> bindOrganization(request, dbSession, o));
writeResponse(request, response, organization);
} catch (OrganizationUpdater.KeyConflictException e) {
@@ -130,6 +148,17 @@ public class CreateAction implements OrganizationsWsAction {
}
}
+ private void bindOrganization(Request request, DbSession dbSession, OrganizationDto organization) {
+ if (organizationAlmBinding == null) {
+ return;
+ }
+ String installationId = request.param(PARAM_INSTALLATION_ID);
+ if (installationId == null) {
+ return;
+ }
+ organizationAlmBinding.bindOrganization(dbSession, organization, installationId);
+ }
+
@CheckForNull
private String getAndCheckKey(Request request) {
String rqstKey = request.param(PARAM_KEY);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java
index 7b1685f8385..ad2a2d80fce 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java
@@ -120,6 +120,7 @@ public class DeleteAction implements OrganizationsWsAction {
deleteGroups(dbSession, organization);
deleteQualityProfiles(dbSession, organization);
deleteQualityGates(dbSession, organization);
+ deleteOrganizationAlmBinding(dbSession, organization);
deleteOrganization(dbSession, organization);
billingValidations.onDelete(new BillingValidations.Organization(organization.getKey(), organization.getUuid()));
@@ -148,16 +149,12 @@ public class DeleteAction implements OrganizationsWsAction {
private void deletePermissions(DbSession dbSession, OrganizationDto organization) {
dbClient.permissionTemplateDao().deleteByOrganization(dbSession, organization.getUuid());
- dbSession.commit();
dbClient.userPermissionDao().deleteByOrganization(dbSession, organization.getUuid());
- dbSession.commit();
dbClient.groupPermissionDao().deleteByOrganization(dbSession, organization.getUuid());
- dbSession.commit();
}
private void deleteGroups(DbSession dbSession, OrganizationDto organization) {
dbClient.groupDao().deleteByOrganization(dbSession, organization.getUuid());
- dbSession.commit();
}
private void deleteQualityProfiles(DbSession dbSession, OrganizationDto organization) {
@@ -174,6 +171,10 @@ public class DeleteAction implements OrganizationsWsAction {
dbClient.qualityGateDao().deleteOrgQualityGatesByOrganization(dbSession, organization);
}
+ private void deleteOrganizationAlmBinding(DbSession dbSession, OrganizationDto organization){
+ dbClient.organizationAlmBindingDao().deleteByOrganization(dbSession, organization);
+ }
+
private void deleteOrganization(DbSession dbSession, OrganizationDto organization) {
Collection<String> uuids = dbClient.organizationMemberDao().selectUserUuidsByOrganizationUuid(dbSession, organization.getUuid());
dbClient.organizationMemberDao().deleteByOrganizationUuid(dbSession, organization.getUuid());
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsSupport.java b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsSupport.java
index 25f59dd801d..9be33f51eed 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsSupport.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsSupport.java
@@ -42,7 +42,6 @@ public class OrganizationsWsSupport {
static final String PARAM_DESCRIPTION = "description";
static final String PARAM_URL = "url";
static final String PARAM_AVATAR_URL = "avatar";
-
static final String PARAM_LOGIN = "login";
private final OrganizationValidation organizationValidation;
@@ -109,10 +108,7 @@ public class OrganizationsWsSupport {
}
Organization.Builder toOrganization(OrganizationDto dto) {
- return toOrganization(Organization.newBuilder(), dto);
- }
-
- Organization.Builder toOrganization(Organization.Builder builder, OrganizationDto dto) {
+ Organization.Builder builder = Organization.newBuilder();
builder
.setName(dto.getName())
.setKey(dto.getKey())
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/SearchAction.java
index d9d9f6835b3..625a16687d7 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/SearchAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/SearchAction.java
@@ -20,15 +20,19 @@
package org.sonar.server.organization.ws;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
+import org.sonar.db.alm.OrganizationAlmBindingDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.organization.OrganizationQuery;
import org.sonar.server.user.UserSession;
@@ -36,6 +40,7 @@ import org.sonarqube.ws.Organizations;
import org.sonarqube.ws.Organizations.Organization;
import static java.util.Collections.emptySet;
+import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.core.util.stream.MoreCollectors.toSet;
import static org.sonar.db.Pagination.forPage;
import static org.sonar.db.organization.OrganizationQuery.newOrganizationQueryBuilder;
@@ -52,12 +57,10 @@ public class SearchAction implements OrganizationsWsAction {
private final DbClient dbClient;
private final UserSession userSession;
- private final OrganizationsWsSupport wsSupport;
- public SearchAction(DbClient dbClient, UserSession userSession, OrganizationsWsSupport wsSupport) {
+ public SearchAction(DbClient dbClient, UserSession userSession) {
this.dbClient = dbClient;
this.userSession = userSession;
- this.wsSupport = wsSupport;
}
@Override
@@ -90,7 +93,7 @@ public class SearchAction implements OrganizationsWsAction {
@Override
public void handle(Request request, Response response) throws Exception {
boolean isMember = request.mandatoryParamAsBoolean(PARAM_MEMBER);
- if (isMember){
+ if (isMember) {
userSession.checkLoggedIn();
}
@@ -100,7 +103,9 @@ public class SearchAction implements OrganizationsWsAction {
Paging paging = buildWsPaging(request, total);
List<OrganizationDto> organizations = dbClient.organizationDao().selectByQuery(dbSession, dbQuery, forPage(paging.getPageIndex()).andSize(paging.getPageSize()));
Set<String> adminOrganizationUuids = searchOrganizationWithAdminPermission(dbSession);
- writeResponse(request, response, organizations, adminOrganizationUuids, paging);
+ Map<String, OrganizationAlmBindingDto> organizationAlmBindingByOrgUuid = dbClient.organizationAlmBindingDao().selectByOrganizations(dbSession, organizations)
+ .stream().collect(MoreCollectors.uniqueIndex(OrganizationAlmBindingDto::getOrganizationUuid));
+ writeResponse(request, response, organizations, adminOrganizationUuids, organizationAlmBindingByOrgUuid, paging);
}
}
@@ -117,20 +122,38 @@ public class SearchAction implements OrganizationsWsAction {
: dbClient.organizationDao().selectByPermission(dbSession, userId, ADMINISTER.getKey()).stream().map(OrganizationDto::getUuid).collect(toSet());
}
- private void writeResponse(Request httpRequest, Response httpResponse, List<OrganizationDto> organizations, Set<String> adminOrganizationUuids, Paging paging) {
+ private static void writeResponse(Request httpRequest, Response httpResponse, List<OrganizationDto> organizations, Set<String> adminOrganizationUuids,
+ Map<String, OrganizationAlmBindingDto> organizationAlmBindingByOrgUuid,
+ Paging paging) {
Organizations.SearchWsResponse.Builder response = Organizations.SearchWsResponse.newBuilder();
response.setPaging(paging);
Organization.Builder wsOrganization = Organization.newBuilder();
organizations
.forEach(o -> {
- boolean isAdmin = adminOrganizationUuids.contains(o.getUuid());
wsOrganization.clear();
+ boolean isAdmin = adminOrganizationUuids.contains(o.getUuid());
wsOrganization.setIsAdmin(isAdmin);
- response.addOrganizations(wsSupport.toOrganization(wsOrganization, o));
+ response.addOrganizations(toOrganization(wsOrganization, o, organizationAlmBindingByOrgUuid.get(o.getUuid())));
});
writeProtobuf(response.build(), httpRequest, httpResponse);
}
+ private static Organization.Builder toOrganization(Organization.Builder builder, OrganizationDto organization, @Nullable OrganizationAlmBindingDto organizationAlmBinding) {
+ builder
+ .setName(organization.getName())
+ .setKey(organization.getKey())
+ .setGuarded(organization.isGuarded());
+ setNullable(organization.getDescription(), builder::setDescription);
+ setNullable(organization.getUrl(), builder::setUrl);
+ setNullable(organization.getAvatarUrl(), builder::setAvatar);
+ if (organizationAlmBinding != null) {
+ builder.setAlm(Organization.Alm.newBuilder()
+ .setKey(organizationAlmBinding.getAlm().getId())
+ .setUrl(organizationAlmBinding.getUrl()));
+ }
+ return builder;
+ }
+
private static Paging buildWsPaging(Request request, int total) {
return Paging.newBuilder()
.setPageIndex(request.mandatoryParamAsInt(Param.PAGE))
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/ws/ComponentAction.java b/server/sonar-server/src/main/java/org/sonar/server/ui/ws/ComponentAction.java
index 4fb3bf2f420..eba36038998 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/ui/ws/ComponentAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/ui/ws/ComponentAction.java
@@ -192,8 +192,10 @@ public class ComponentAction implements NavigationWsAction {
.map(ALM::getId)
.map(String::valueOf)
.orElseThrow(() -> new IllegalStateException("Alm binding id DB has no ALM id"));
- json.prop("almId", almId)
- .prop("almRepoUrl", b.getUrl());
+ json.name("alm").beginObject()
+ .prop("key", almId)
+ .prop("url", b.getUrl())
+ .endObject();
});
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/organization/OrganizationUpdaterImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/organization/OrganizationUpdaterImplTest.java
index f389e9bc947..8d1b7019024 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/organization/OrganizationUpdaterImplTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/organization/OrganizationUpdaterImplTest.java
@@ -22,6 +22,7 @@ package org.sonar.server.organization;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
+import java.util.function.Consumer;
import org.apache.commons.lang.RandomStringUtils;
import org.junit.Rule;
import org.junit.Test;
@@ -90,6 +91,9 @@ public class OrganizationUpdaterImplTest {
private System2 system2 = new TestSystem2().setNow(A_DATE);
+ private static Consumer<OrganizationDto> EMPTY_ORGANIZATION_CONSUMER = o -> {
+ };
+
@Rule
public DbTester db = DbTester.create(system2);
@Rule
@@ -122,7 +126,7 @@ public class OrganizationUpdaterImplTest {
UserDto user = db.users().insertUser();
db.qualityGates().insertBuiltInQualityGate();
- underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION);
+ underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, EMPTY_ORGANIZATION_CONSUMER);
OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, FULL_POPULATED_NEW_ORGANIZATION.getKey()).get();
assertThat(organization.getUuid()).isNotEmpty();
@@ -143,7 +147,7 @@ public class OrganizationUpdaterImplTest {
builtInQProfileRepositoryRule.initialize();
db.qualityGates().insertBuiltInQualityGate();
- underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION);
+ underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, EMPTY_ORGANIZATION_CONSUMER);
verifyGroupOwners(user, FULL_POPULATED_NEW_ORGANIZATION.getKey(), FULL_POPULATED_NEW_ORGANIZATION.getName());
}
@@ -154,7 +158,7 @@ public class OrganizationUpdaterImplTest {
builtInQProfileRepositoryRule.initialize();
db.qualityGates().insertBuiltInQualityGate();
- underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION);
+ underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, EMPTY_ORGANIZATION_CONSUMER);
verifyMembersGroup(user, FULL_POPULATED_NEW_ORGANIZATION.getKey());
}
@@ -168,7 +172,7 @@ public class OrganizationUpdaterImplTest {
underTest.create(dbSession, user, newOrganizationBuilder()
.setKey("key")
.setName("name")
- .build());
+ .build(), EMPTY_ORGANIZATION_CONSUMER);
OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, "key").get();
assertThat(organization.getKey()).isEqualTo("key");
@@ -185,7 +189,7 @@ public class OrganizationUpdaterImplTest {
UserDto user = db.users().insertUser();
db.qualityGates().insertBuiltInQualityGate();
- underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION);
+ underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, EMPTY_ORGANIZATION_CONSUMER);
OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, FULL_POPULATED_NEW_ORGANIZATION.getKey()).get();
GroupDto ownersGroup = dbClient.groupDao().selectByName(dbSession, organization.getUuid(), "Owners").get();
@@ -210,7 +214,7 @@ public class OrganizationUpdaterImplTest {
builtInQProfileRepositoryRule.initialize();
db.qualityGates().insertBuiltInQualityGate();
- OrganizationDto result = underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION);
+ OrganizationDto result = underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, EMPTY_ORGANIZATION_CONSUMER);
assertThat(dbClient.organizationMemberDao().select(dbSession, result.getUuid(), user.getId())).isPresent();
assertThat(userIndex.search(UserQuery.builder().setOrganizationUuid(result.getUuid()).setTextQuery(user.getLogin()).build(), new SearchOptions()).getTotal()).isEqualTo(1L);
@@ -226,7 +230,7 @@ public class OrganizationUpdaterImplTest {
UserDto user = db.users().insertUser();
db.qualityGates().insertBuiltInQualityGate();
- underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION);
+ underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, EMPTY_ORGANIZATION_CONSUMER);
OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, FULL_POPULATED_NEW_ORGANIZATION.getKey()).get();
List<QProfileDto> profiles = dbClient.qualityProfileDao().selectOrderedByOrganizationUuid(dbSession, organization);
@@ -252,20 +256,35 @@ public class OrganizationUpdaterImplTest {
builtInQProfileRepositoryRule.initialize();
UserDto user = db.users().insertUser();
- underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION);
+ underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, o -> {
+ });
OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, FULL_POPULATED_NEW_ORGANIZATION.getKey()).get();
assertThat(dbClient.qualityGateDao().selectDefault(dbSession, organization).getUuid()).isEqualTo(builtInQualityGate.getUuid());
}
@Test
+ public void create_calls_consumer() throws OrganizationUpdater.KeyConflictException {
+ UserDto user = db.users().insertUser();
+ builtInQProfileRepositoryRule.initialize();
+ db.qualityGates().insertBuiltInQualityGate();
+ Boolean[] isConsumerCalled = new Boolean[]{false};
+
+ underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, o -> {
+ isConsumerCalled[0] = true;
+ });
+
+ assertThat(isConsumerCalled[0]).isEqualTo(true);
+ }
+
+ @Test
public void create_throws_NPE_if_NewOrganization_arg_is_null() throws OrganizationUpdater.KeyConflictException {
UserDto user = db.users().insertUser();
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("newOrganization can't be null");
- underTest.create(dbSession, user, null);
+ underTest.create(dbSession, user, null, EMPTY_ORGANIZATION_CONSUMER);
}
@Test
@@ -307,7 +326,7 @@ public class OrganizationUpdaterImplTest {
private void createThrowsExceptionThrownByOrganizationValidation(UserDto user) throws OrganizationUpdater.KeyConflictException {
try {
- underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION);
+ underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, EMPTY_ORGANIZATION_CONSUMER);
fail(exceptionThrownByOrganizationValidation + " should have been thrown");
} catch (IllegalArgumentException e) {
assertThat(e).isSameAs(exceptionThrownByOrganizationValidation);
@@ -322,7 +341,7 @@ public class OrganizationUpdaterImplTest {
expectedException.expect(OrganizationUpdater.KeyConflictException.class);
expectedException.expectMessage("Organization key '" + FULL_POPULATED_NEW_ORGANIZATION.getKey() + "' is already used");
- underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION);
+ underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, EMPTY_ORGANIZATION_CONSUMER);
}
@Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/organization/ws/CreateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/organization/ws/CreateActionTest.java
index 362b1be4bdc..3fd6feef739 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/organization/ws/CreateActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/organization/ws/CreateActionTest.java
@@ -50,6 +50,7 @@ import org.sonar.db.user.UserMembershipQuery;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.organization.OrganizationAlmBinding;
import org.sonar.server.organization.OrganizationUpdater;
import org.sonar.server.organization.OrganizationUpdaterImpl;
import org.sonar.server.organization.OrganizationValidation;
@@ -72,7 +73,11 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.sonar.core.config.CorePropertyDefinitions.ORGANIZATIONS_ANYONE_CAN_CREATE;
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_NAME;
import static org.sonar.server.organization.ws.OrganizationsWsTestSupport.STRING_257_CHARS_LONG;
@@ -107,11 +112,12 @@ public class CreateActionTest {
userIndexer,
mock(BuiltInQProfileRepository.class), new DefaultGroupCreatorImpl(dbClient), permissionService);
private TestOrganizationFlags organizationFlags = TestOrganizationFlags.standalone().setEnabled(true);
+ private OrganizationAlmBinding organizationAlmBinding = mock(OrganizationAlmBinding.class);
private WsActionTester wsTester = new WsActionTester(
new CreateAction(settings.asConfig(), userSession, dbClient, new OrganizationsWsSupport(organizationValidation),
organizationValidation,
- organizationUpdater, organizationFlags));
+ organizationUpdater, organizationFlags, organizationAlmBinding));
@Test
public void create_organization() {
@@ -252,6 +258,47 @@ public class CreateActionTest {
}
@Test
+ public void bind_organization_when_installation_id_is_set() {
+ createUserAndLogInAsSystemAdministrator();
+ db.qualityGates().insertBuiltInQualityGate();
+
+ wsTester.newRequest()
+ .setParam(PARAM_NAME, "foo")
+ .setParam("installationId", "ABCD")
+ .execute();
+
+ verify(organizationAlmBinding).bindOrganization(any(DbSession.class), any(OrganizationDto.class), eq("ABCD"));
+ }
+
+ @Test
+ public void does_not_bind_organization_when_organizationAlmBinding_is_null() {
+ wsTester = new WsActionTester(
+ new CreateAction(settings.asConfig(), userSession, dbClient, new OrganizationsWsSupport(organizationValidation),
+ organizationValidation, organizationUpdater, organizationFlags, null));
+ createUserAndLogInAsSystemAdministrator();
+ db.qualityGates().insertBuiltInQualityGate();
+
+ wsTester.newRequest()
+ .setParam(PARAM_NAME, "foo")
+ .setParam("installationId", "ABCD")
+ .execute();
+
+ verifyZeroInteractions(organizationAlmBinding);
+ }
+
+ @Test
+ public void does_not_bind_organization_when_installation_id_is_not_set() {
+ createUserAndLogInAsSystemAdministrator();
+ db.qualityGates().insertBuiltInQualityGate();
+
+ wsTester.newRequest()
+ .setParam(PARAM_NAME, "foo")
+ .execute();
+
+ verifyZeroInteractions(organizationAlmBinding);
+ }
+
+ @Test
public void request_succeeds_if_user_is_system_administrator_and_logged_in_users_cannot_create_organizations() {
createUserAndLogInAsSystemAdministrator();
db.qualityGates().insertBuiltInQualityGate();
@@ -520,7 +567,7 @@ public class CreateActionTest {
assertThat(action.isInternal()).isTrue();
assertThat(action.since()).isEqualTo("6.2");
assertThat(action.handler()).isNotNull();
- assertThat(action.params()).hasSize(5);
+ assertThat(action.params()).hasSize(6);
assertThat(action.responseExample()).isEqualTo(getClass().getResource("create-example.json"));
assertThat(action.param("name"))
@@ -547,6 +594,9 @@ public class CreateActionTest {
.matches(param -> !param.isRequired())
.matches(param -> "https://www.foo.com/foo.png".equals(param.exampleValue()))
.matches(param -> param.description() != null);
+ assertThat(action.param("installationId"))
+ .matches(param -> !param.isRequired())
+ .matches(param -> param.isInternal());
}
@Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/organization/ws/DeleteActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/organization/ws/DeleteActionTest.java
index 3d709dc4c99..3acddd3f63c 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/organization/ws/DeleteActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/organization/ws/DeleteActionTest.java
@@ -37,6 +37,8 @@ import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
+import org.sonar.db.alm.ALM;
+import org.sonar.db.alm.AlmAppInstallDto;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.component.ResourceTypesRule;
@@ -76,6 +78,8 @@ import org.sonar.server.ws.WsActionTester;
import static com.google.common.collect.ImmutableList.of;
import static java.util.Arrays.asList;
import static java.util.Collections.emptySet;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
@@ -542,6 +546,21 @@ public class DeleteActionTest {
verify(billingValidationsProxy).onDelete(any(BillingValidations.Organization.class));
}
+ @Test
+ public void delete_organization_alm_binding() {
+ OrganizationDto organization = db.organizations().insert();
+ String installationId = randomAlphanumeric(10);
+ db.getDbClient().almAppInstallDao().insertOrUpdate(db.getSession(), ALM.GITHUB, randomAlphabetic(13), false, installationId);
+ AlmAppInstallDto almAppInstall = db.getDbClient().almAppInstallDao().selectByInstallationId(db.getSession(), ALM.GITHUB, installationId).get();
+ db.getDbClient().organizationAlmBindingDao().insert(db.getSession(), organization, almAppInstall, randomAlphabetic(10), db.users().insertUser().getUuid());
+ db.commit();
+ logInAsAdministrator(organization);
+
+ sendRequest(organization);
+
+ assertThat(db.getDbClient().organizationAlmBindingDao().selectByOrganization(db.getSession(), organization)).isNotPresent();
+ }
+
@DataProvider
public static Object[][] indexOfFailingProjectDeletion() {
return new Object[][] {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/organization/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/organization/ws/SearchActionTest.java
index 1f3db59c0d8..7d54fcb892a 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/organization/ws/SearchActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/organization/ws/SearchActionTest.java
@@ -22,6 +22,7 @@ package org.sonar.server.organization.ws;
import com.google.common.base.Joiner;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.Random;
import javax.annotation.Nullable;
import org.junit.Rule;
@@ -31,11 +32,12 @@ import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.core.util.Uuids;
import org.sonar.db.DbTester;
+import org.sonar.db.alm.AlmAppInstallDto;
+import org.sonar.db.alm.OrganizationAlmBindingDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.exceptions.UnauthorizedException;
-import org.sonar.server.organization.OrganizationValidationImpl;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
@@ -45,6 +47,8 @@ import org.sonarqube.ws.Organizations.Organization;
import org.sonarqube.ws.Organizations.SearchWsResponse;
import static java.lang.String.valueOf;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.Mockito.mock;
@@ -68,7 +72,7 @@ public class SearchActionTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
- private SearchAction underTest = new SearchAction(db.getDbClient(), userSession, new OrganizationsWsSupport(new OrganizationValidationImpl()));
+ private SearchAction underTest = new SearchAction(db.getDbClient(), userSession);
private WsActionTester ws = new WsActionTester(underTest);
@Test
@@ -213,6 +217,21 @@ public class SearchActionTest {
}
@Test
+ public void return_alm_info() {
+ OrganizationDto organization = db.organizations().insert();
+ AlmAppInstallDto almAppInstall = db.alm().insertAlmAppInstall();
+ OrganizationAlmBindingDto organizationAlmBinding = db.alm().insertOrganizationAlmBinding(organization, almAppInstall);
+ OrganizationDto organizationNotBoundToAlm = db.organizations().insert();
+
+ SearchWsResponse result = call(ws.newRequest());
+
+ Map<String, Organization> orgByKey = result.getOrganizationsList().stream().collect(toMap(Organization::getKey, identity()));
+ assertThat(orgByKey.get(organization.getKey()).getAlm().getKey()).isEqualTo(organizationAlmBinding.getAlm().getId());
+ assertThat(orgByKey.get(organization.getKey()).getAlm().getUrl()).isEqualTo(organizationAlmBinding.getUrl());
+ assertThat(orgByKey.get(organizationNotBoundToAlm.getKey()).hasAlm()).isEqualTo(false);
+ }
+
+ @Test
public void request_on_empty_db_returns_an_empty_organization_list() {
assertThat(executeRequestAndReturnList(null, null)).isEmpty();
assertThat(executeRequestAndReturnList(null, 1)).isEmpty();
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ui/ws/ComponentActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ui/ws/ComponentActionTest.java
index 9edc7b47337..19e539c36df 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/ui/ws/ComponentActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/ui/ws/ComponentActionTest.java
@@ -606,7 +606,19 @@ public class ComponentActionTest {
userSession.addProjectPermission(UserRole.USER, project);
init();
- executeAndVerify(project.getDbKey(), "return_alm_infos_on_project.json");
+ String json = execute(project.getKey());
+
+ assertJson(json).isSimilarTo("{\n" +
+ " \"organization\": \"my-org\",\n" +
+ " \"key\": \"polop\",\n" +
+ " \"id\": \"abcd\",\n" +
+ " \"name\": \"Polop\",\n" +
+ " \"description\": \"test project\",\n" +
+ " \"alm\": {\n" +
+ " \"key\": \"bitbucketcloud\",\n" +
+ " \"url\": \"http://bitbucket.org/foo/bar\"\n" +
+ " }\n" +
+ "}\n");
}
@Test
@@ -618,7 +630,18 @@ public class ComponentActionTest {
userSession.addProjectPermission(UserRole.USER, project);
init();
- executeAndVerify(module.getDbKey(), "return_alm_infos_on_module.json");
+ String json = execute(module.getKey());
+
+ assertJson(json).isSimilarTo("{\n" +
+ " \"organization\": \"my-org\",\n" +
+ " \"key\": \"palap\",\n" +
+ " \"id\": \"bcde\",\n" +
+ " \"name\": \"Palap\",\n" +
+ " \"alm\": {\n" +
+ " \"key\": \"bitbucketcloud\",\n" +
+ " \"url\": \"http://bitbucket.org/foo/bar\"\n" +
+ " }\n" +
+ "}\n");
}
@Test
@@ -630,11 +653,24 @@ public class ComponentActionTest {
userSession.addProjectPermission(UserRole.USER, project);
init();
- verify(ws.newRequest()
- .setParam("componentKey", project.getDbKey())
+ String json = ws.newRequest()
+ .setParam("componentKey", project.getKey())
.setParam("branch", branch.getBranch())
.execute()
- .getInput(), "return_alm_infos_on_branch.json");
+ .getInput();
+
+ assertJson(json).isSimilarTo("{\n" +
+ " \"organization\": \"my-org\",\n" +
+ " \"key\": \"polop\",\n" +
+ " \"id\": \"xyz\",\n" +
+ " \"branch\": \"feature1\"," +
+ " \"name\": \"Polop\",\n" +
+ " \"description\": \"test project\",\n" +
+ " \"alm\": {\n" +
+ " \"key\": \"bitbucketcloud\",\n" +
+ " \"url\": \"http://bitbucket.org/foo/bar\"\n" +
+ " }\n" +
+ "}\n");
}
private ComponentDto insertOrganizationAndProject() {
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/ui/ws/ComponentActionTest/return_alm_infos_on_branch.json b/server/sonar-server/src/test/resources/org/sonar/server/ui/ws/ComponentActionTest/return_alm_infos_on_branch.json
deleted file mode 100644
index 968b1094a5c..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/ui/ws/ComponentActionTest/return_alm_infos_on_branch.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "organization": "my-org",
- "key": "polop",
- "id": "xyz",
- "branch": "feature1",
- "name": "Polop",
- "description": "test project",
- "almId": "bitbucketcloud",
- "almRepoUrl": "http://bitbucket.org/foo/bar"
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/ui/ws/ComponentActionTest/return_alm_infos_on_module.json b/server/sonar-server/src/test/resources/org/sonar/server/ui/ws/ComponentActionTest/return_alm_infos_on_module.json
deleted file mode 100644
index 0078c9f13c4..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/ui/ws/ComponentActionTest/return_alm_infos_on_module.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "organization": "my-org",
- "key": "palap",
- "id": "bcde",
- "name": "Palap",
- "almId": "bitbucketcloud",
- "almRepoUrl": "http://bitbucket.org/foo/bar"
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/ui/ws/ComponentActionTest/return_alm_infos_on_project.json b/server/sonar-server/src/test/resources/org/sonar/server/ui/ws/ComponentActionTest/return_alm_infos_on_project.json
deleted file mode 100644
index 6ac04350a84..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/ui/ws/ComponentActionTest/return_alm_infos_on_project.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "organization": "my-org",
- "key": "polop",
- "id": "abcd",
- "name": "Polop",
- "description": "test project",
- "almId": "bitbucketcloud",
- "almRepoUrl": "http://bitbucket.org/foo/bar"
-}
diff --git a/sonar-ws/src/main/protobuf/ws-organizations.proto b/sonar-ws/src/main/protobuf/ws-organizations.proto
index 172bf31d85c..1d729266ddc 100644
--- a/sonar-ws/src/main/protobuf/ws-organizations.proto
+++ b/sonar-ws/src/main/protobuf/ws-organizations.proto
@@ -61,6 +61,12 @@ message Organization {
optional string avatar = 5;
optional bool guarded = 6;
optional bool isAdmin = 7;
+ optional Alm alm = 8;
+
+ message Alm {
+ optional string key = 1;
+ optional string url = 2;
+ }
}
message User {