* Return AlmAppInstallDto in select methods of AlmAppInstallDao, this is required in order to be able to more easily link an OrganizationDto to a AlmAppInstallDto in next commit
* Create ORGANIZATION_ALM_BINDINGS table
* Bind organization with installation when creating organization
* Delete alm binding when removing organization
* Delete alm binding when uninstalling ALM application
* Return ALM info in api/organizations/search
* Ensure user is admin to return Bitbucket team/user details
+ 3 // CeCleaningModule + its content
+ 4 // WebhookModule
+ 1 // CeDistributedInformation
- );
+ );
assertThat(picoContainer.getParent().getComponentAdapters()).hasSize(
CONTAINER_ITSELF
+ 8 // level 3
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
"metrics",
"notifications",
"organizations",
+ "organization_alm_bindings",
"organization_members",
"org_qprofiles",
"org_quality_gates",
);
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");
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;
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;
GroupMembershipDao.class,
GroupPermissionDao.class,
AlmAppInstallDao.class,
- ProjectAlmBindingsDao.class,
+ ProjectAlmBindingDao.class,
InternalPropertiesDao.class,
IssueChangeDao.class,
IssueDao.class,
MeasureDao.class,
MetricDao.class,
NotificationQueueDao.class,
+ OrganizationAlmBindingDao.class,
OrganizationDao.class,
OrganizationMemberDao.class,
PermissionTemplateCharacteristicDao.class,
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;
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;
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;
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;
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);
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) {
return almAppInstallDao;
}
- public ProjectAlmBindingsDao projectAlmBindingsDao() {
- return projectAlmBindingsDao;
+ public ProjectAlmBindingDao projectAlmBindingsDao() {
+ return projectAlmBindingDao;
}
public SchemaMigrationDao schemaMigrationDao() {
public ProjectMappingsDao projectMappingsDao() {
return projectMappingsDao;
}
+
+ public OrganizationAlmBindingDao organizationAlmBindingDao() {
+ return organizationAlmBindingDao;
+ }
}
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;
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,
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;
/**
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) {
}
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) {
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();
--- /dev/null
+/*
+ * 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
+ }
+
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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.Objects;
+import java.util.Optional;
+import javax.annotation.Nullable;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.Dao;
+import org.sonar.db.DbSession;
+
+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 ProjectAlmBindingDao implements Dao {
+
+ private final System2 system2;
+ private final UuidFactory uuidFactory;
+
+ public ProjectAlmBindingDao(System2 system2, UuidFactory uuidFactory) {
+ this.system2 = system2;
+ this.uuidFactory = uuidFactory;
+ }
+
+ public void insertOrUpdate(DbSession dbSession, ALM alm, String repoId, String projectUuid, @Nullable String githubSlug, String url) {
+ checkAlm(alm);
+ checkRepoId(repoId);
+ checkArgument(isNotEmpty(projectUuid), "projectUuid can't be null nor empty");
+ checkArgument(isNotEmpty(url), "url can't be null nor empty");
+
+ ProjectAlmBindingMapper mapper = getMapper(dbSession);
+ long now = system2.now();
+
+ if (mapper.update(alm.getId(), repoId, projectUuid, githubSlug, url, now) == 0) {
+ mapper.insert(uuidFactory.create(), alm.getId(), repoId, projectUuid, githubSlug, url, now);
+ }
+ }
+
+ public Optional<ProjectAlmBindingDto> selectByProjectUuid(DbSession session, String projectUuid) {
+ return Optional.ofNullable(getMapper(session).selectByProjectUuid(projectUuid));
+ }
+
+ /**
+ * Gets a list of bindings by their repo_id. The result does NOT contain {@code null} values for bindings not found, so
+ * the size of result may be less than the number of ids.
+ * <p>Results may be in a different order as input ids.</p>
+ */
+ public List<ProjectAlmBindingDto> selectByRepoIds(final DbSession session, ALM alm, Collection<String> repoIds) {
+ return executeLargeInputs(repoIds, partionnedIds -> getMapper(session).selectByRepoIds(alm.getId(), partionnedIds));
+ }
+
+ public Optional<ProjectAlmBindingDto> selectByRepoId(final DbSession session, ALM alm, String repoId) {
+ return Optional.ofNullable(getMapper(session).selectByRepoId(alm.getId(), repoId));
+ }
+
+ public Optional<String> findProjectKey(DbSession dbSession, ALM alm, String repoId) {
+ checkAlm(alm);
+ checkRepoId(repoId);
+
+ ProjectAlmBindingMapper mapper = getMapper(dbSession);
+ return Optional.ofNullable(mapper.selectProjectKey(alm.getId(), repoId));
+ }
+
+ private static void checkAlm(@Nullable ALM alm) {
+ Objects.requireNonNull(alm, "alm can't be null");
+ }
+
+ private static void checkRepoId(@Nullable String repoId) {
+ checkArgument(isNotEmpty(repoId), "repoId can't be null nor empty");
+ }
+
+ private static ProjectAlmBindingMapper getMapper(DbSession dbSession) {
+ return dbSession.getMapper(ProjectAlmBindingMapper.class);
+ }
+
+}
--- /dev/null
+/*
+ * 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.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.ibatis.annotations.Param;
+
+public interface ProjectAlmBindingMapper {
+
+ int bindingCount(@Param("almId") String almId, @Param("repoId") String repoId);
+
+ void insert(@Param("uuid") String uuid, @Param("almId") String almId, @Param("repoId") String repoId, @Param("projectUuid") String projectUuid,
+ @Nullable @Param("githubSlug") String githubSlug, @Param("url") String url, @Param("now") long now);
+
+ int update(@Param("almId") String almId, @Param("repoId") String repoId, @Param("projectUuid") String projectUuid,
+ @Nullable @Param("githubSlug") String githubSlug, @Param("url") String url, @Param("now") long now);
+
+ List<ProjectAlmBindingDto> selectByRepoIds(@Param("almId") String almId, @Param("repoIds") List<String> repoIds);
+
+ ProjectAlmBindingDto selectByRepoId(@Param("almId") String almId, @Param("repoId") String repoId);
+
+ ProjectAlmBindingDto selectByProjectUuid(@Param("projectUuid") String projectUuid);
+
+ @CheckForNull
+ String selectProjectKey(@Param("almId") String almId, @Param("repoId") String repoId);
+}
+++ /dev/null
-/*
- * 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.Objects;
-import java.util.Optional;
-import javax.annotation.Nullable;
-import org.sonar.api.utils.System2;
-import org.sonar.core.util.UuidFactory;
-import org.sonar.db.Dao;
-import org.sonar.db.DbSession;
-
-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 {
-
- private final System2 system2;
- private final UuidFactory uuidFactory;
-
- public ProjectAlmBindingsDao(System2 system2, UuidFactory uuidFactory) {
- this.system2 = system2;
- this.uuidFactory = uuidFactory;
- }
-
- public void insertOrUpdate(DbSession dbSession, ALM alm, String repoId, String projectUuid, @Nullable String githubSlug, String url) {
- checkAlm(alm);
- checkRepoId(repoId);
- checkArgument(isNotEmpty(projectUuid), "projectUuid can't be null nor empty");
- checkArgument(isNotEmpty(url), "url can't be null nor empty");
-
- ProjectAlmBindingsMapper mapper = getMapper(dbSession);
- long now = system2.now();
-
- if (mapper.update(alm.getId(), repoId, projectUuid, githubSlug, url, now) == 0) {
- mapper.insert(uuidFactory.create(), alm.getId(), repoId, projectUuid, githubSlug, url, now);
- }
- }
-
- public Optional<ProjectAlmBindingDto> selectByProjectUuid(DbSession session, String projectUuid) {
- return Optional.ofNullable(getMapper(session).selectByProjectUuid(projectUuid));
- }
-
- /**
- * Gets a list of bindings by their repo_id. The result does NOT contain {@code null} values for bindings not found, so
- * the size of result may be less than the number of ids.
- * <p>Results may be in a different order as input ids.</p>
- */
- public List<ProjectAlmBindingDto> selectByRepoIds(final DbSession session, ALM alm, Collection<String> repoIds) {
- return executeLargeInputs(repoIds, partionnedIds -> getMapper(session).selectByRepoIds(alm.getId(), partionnedIds));
- }
-
- public Optional<ProjectAlmBindingDto> selectByRepoId(final DbSession session, ALM alm, String repoId) {
- return Optional.ofNullable(getMapper(session).selectByRepoId(alm.getId(), repoId));
- }
-
- public Optional<String> findProjectKey(DbSession dbSession, ALM alm, String repoId) {
- checkAlm(alm);
- checkRepoId(repoId);
-
- ProjectAlmBindingsMapper mapper = getMapper(dbSession);
- return Optional.ofNullable(mapper.selectProjectKey(alm.getId(), repoId));
- }
-
- private static void checkAlm(@Nullable ALM alm) {
- Objects.requireNonNull(alm, "alm can't be null");
- }
-
- private static void checkRepoId(@Nullable String repoId) {
- checkArgument(isNotEmpty(repoId), "repoId can't be null nor empty");
- }
-
- private static ProjectAlmBindingsMapper getMapper(DbSession dbSession) {
- return dbSession.getMapper(ProjectAlmBindingsMapper.class);
- }
-
-}
+++ /dev/null
-/*
- * 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.List;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.apache.ibatis.annotations.Param;
-
-public interface ProjectAlmBindingsMapper {
-
- int bindingCount(@Param("almId") String almId, @Param("repoId") String repoId);
-
- void insert(@Param("uuid") String uuid, @Param("almId") String almId, @Param("repoId") String repoId, @Param("projectUuid") String projectUuid,
- @Nullable @Param("githubSlug") String githubSlug, @Param("url") String url, @Param("now") long now);
-
- int update(@Param("almId") String almId, @Param("repoId") String repoId, @Param("projectUuid") String projectUuid,
- @Nullable @Param("githubSlug") String githubSlug, @Param("url") String url, @Param("now") long now);
-
- List<ProjectAlmBindingDto> selectByRepoIds(@Param("almId") String almId, @Param("repoIds") List<String> repoIds);
-
- ProjectAlmBindingDto selectByRepoId(@Param("almId") String almId, @Param("repoId") String repoId);
-
- ProjectAlmBindingDto selectByProjectUuid(@Param("projectUuid") String projectUuid);
-
- @CheckForNull
- String selectProjectKey(@Param("almId") String almId, @Param("repoId") String repoId);
-}
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
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">
--- /dev/null
+<?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>
--- /dev/null
+<?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.ProjectAlmBindingMapper">
+
+ <sql id="columns">
+ uuid,
+ alm_id as rawAlmId,
+ repo_id as repoId,
+ project_uuid as projectUuid,
+ github_slug as githubSlug,
+ url
+ </sql>
+
+ <select id="bindingCount" parameterType="Map" resultType="int">
+ select
+ count(*) as count
+ from
+ project_alm_bindings
+ where
+ alm_id = #{almId, jdbcType=VARCHAR}
+ and repo_id = #{repoId, jdbcType=VARCHAR}
+ </select>
+
+ <insert id="insert" parameterType="Map" useGeneratedKeys="false">
+ insert into project_alm_bindings
+ (
+ uuid,
+ alm_id,
+ repo_id,
+ project_uuid,
+ github_slug,
+ url,
+ created_at,
+ updated_at
+ )
+ values (
+ #{uuid, jdbcType=VARCHAR},
+ #{almId, jdbcType=VARCHAR},
+ #{repoId, jdbcType=VARCHAR},
+ #{projectUuid, jdbcType=VARCHAR},
+ #{githubSlug, jdbcType=VARCHAR},
+ #{url, jdbcType=VARCHAR},
+ #{now, jdbcType=BIGINT},
+ #{now, jdbcType=BIGINT}
+ )
+ </insert>
+
+ <update id="update" parameterType="map">
+ update project_alm_bindings
+ set
+ project_uuid = #{projectUuid, jdbcType=VARCHAR},
+ github_slug = #{githubSlug, jdbcType=VARCHAR},
+ url = #{url, jdbcType=VARCHAR},
+ updated_at = #{now, jdbcType=BIGINT}
+ where
+ alm_id = #{almId, jdbcType=VARCHAR}
+ and repo_id = #{repoId, jdbcType=VARCHAR}
+ </update>
+
+ <select id="selectByRepoIds" parameterType="map" resultType="ProjectAlmBinding">
+ select
+ <include refid="columns"/>
+ from
+ project_alm_bindings
+ where
+ alm_id = #{almId, jdbcType=VARCHAR}
+ and repo_id in
+ <foreach collection="repoIds" open="(" close=")" item="repoId" separator=",">
+ #{repoId,jdbcType=VARCHAR}
+ </foreach>
+ </select>
+
+ <select id="selectByRepoId" parameterType="map" resultType="ProjectAlmBinding">
+ select
+ <include refid="columns"/>
+ from
+ project_alm_bindings
+ where
+ alm_id = #{almId, jdbcType=VARCHAR}
+ and repo_id = #{repoId, jdbcType=VARCHAR}
+ </select>
+
+ <select id="selectByProjectUuid" parameterType="map" resultType="ProjectAlmBinding">
+ select
+ <include refid="columns"/>
+ from
+ project_alm_bindings
+ where
+ project_uuid = #{projectUuid, jdbcType=VARCHAR}
+ </select>
+
+ <select id="selectProjectKey" parameterType="Map" resultType="String">
+ select
+ p.kee as projectKey
+ from
+ project_alm_bindings b
+ inner join projects p
+ on b.project_uuid = p.project_uuid
+ where
+ alm_id = #{almId, jdbcType=VARCHAR}
+ and repo_id = #{repoId, jdbcType=VARCHAR}
+ </select>
+
+</mapper>
+++ /dev/null
-<?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">
-
- <sql id="columns">
- uuid,
- alm_id as rawAlmId,
- repo_id as repoId,
- project_uuid as projectUuid,
- github_slug as githubSlug,
- url
- </sql>
-
- <select id="bindingCount" parameterType="Map" resultType="int">
- select
- count(*) as count
- from
- project_alm_bindings
- where
- alm_id = #{almId, jdbcType=VARCHAR}
- and repo_id = #{repoId, jdbcType=VARCHAR}
- </select>
-
- <insert id="insert" parameterType="Map" useGeneratedKeys="false">
- insert into project_alm_bindings
- (
- uuid,
- alm_id,
- repo_id,
- project_uuid,
- github_slug,
- url,
- created_at,
- updated_at
- )
- values (
- #{uuid, jdbcType=VARCHAR},
- #{almId, jdbcType=VARCHAR},
- #{repoId, jdbcType=VARCHAR},
- #{projectUuid, jdbcType=VARCHAR},
- #{githubSlug, jdbcType=VARCHAR},
- #{url, jdbcType=VARCHAR},
- #{now, jdbcType=BIGINT},
- #{now, jdbcType=BIGINT}
- )
- </insert>
-
- <update id="update" parameterType="map">
- update project_alm_bindings
- set
- project_uuid = #{projectUuid, jdbcType=VARCHAR},
- github_slug = #{githubSlug, jdbcType=VARCHAR},
- url = #{url, jdbcType=VARCHAR},
- updated_at = #{now, jdbcType=BIGINT}
- where
- alm_id = #{almId, jdbcType=VARCHAR}
- and repo_id = #{repoId, jdbcType=VARCHAR}
- </update>
-
- <select id="selectByRepoIds" parameterType="map" resultType="ProjectAlmBinding">
- select
- <include refid="columns"/>
- from
- project_alm_bindings
- where
- alm_id = #{almId, jdbcType=VARCHAR}
- and repo_id in
- <foreach collection="repoIds" open="(" close=")" item="repoId" separator=",">
- #{repoId,jdbcType=VARCHAR}
- </foreach>
- </select>
-
- <select id="selectByRepoId" parameterType="map" resultType="ProjectAlmBinding">
- select
- <include refid="columns"/>
- from
- project_alm_bindings
- where
- alm_id = #{almId, jdbcType=VARCHAR}
- and repo_id = #{repoId, jdbcType=VARCHAR}
- </select>
-
- <select id="selectByProjectUuid" parameterType="map" resultType="ProjectAlmBinding">
- select
- <include refid="columns"/>
- from
- project_alm_bindings
- where
- project_uuid = #{projectUuid, jdbcType=VARCHAR}
- </select>
-
- <select id="selectProjectKey" parameterType="Map" resultType="String">
- select
- p.kee as projectKey
- from
- project_alm_bindings b
- inner join projects p
- on b.project_uuid = p.project_uuid
- where
- alm_id = #{almId, jdbcType=VARCHAR}
- and repo_id = #{repoId, jdbcType=VARCHAR}
- </select>
-
-</mapper>
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);
}
}
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;
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));
this.pluginDbTester = new PluginDbTester(this);
this.webhookDbTester = new WebhookDbTester(this);
this.webhookDeliveryDbTester = new WebhookDeliveryDbTester(this);
+ this.almDbTester = new AlmDbTester(this);
}
public static DbTester create() {
return webhookDeliveryDbTester;
}
+ public AlmDbTester alm() {
+ return almDbTester;
+ }
+
@Override
protected void after() {
if (session != null) {
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
}
@Test
- public void delete_doesn_t_fail() {
+ public void delete_does_not_fail() {
assertThatAlmAppInstall(GITHUB, A_OWNER).doesNotExist();
underTest.delete(dbSession, GITHUB, A_OWNER);
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)
}
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);
}
--- /dev/null
+/*
+ * 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();
+ }
+
+}
--- /dev/null
+/*
+ * 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();
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import javax.annotation.Nullable;
+import org.assertj.core.api.AbstractAssert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+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.component.ComponentDto;
+import org.sonar.db.component.ComponentTesting;
+
+import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.db.alm.ALM.BITBUCKETCLOUD;
+import static org.sonar.db.alm.ALM.GITHUB;
+
+public class ProjectAlmBindingDaoTest {
+
+ private static final String A_UUID = "abcde1234";
+ private static final String ANOTHER_UUID = "xyz789";
+ private static final String EMPTY_STRING = "";
+
+ private static final String A_REPO = "my_repo";
+ private static final String ANOTHER_REPO = "another_repo";
+
+ private static final String A_GITHUB_SLUG = null;
+ private static final String ANOTHER_GITHUB_SLUG = "example/foo";
+
+ private static final String A_URL = "foo url";
+ private static final String ANOTHER_URL = "bar url";
+
+ private static final long DATE = 1_600_000_000_000L;
+ private static final long DATE_LATER = 1_700_000_000_000L;
+
+ private System2 system2 = mock(System2.class);
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ @Rule
+ public DbTester dbTester = DbTester.create(system2);
+ private DbClient dbClient = dbTester.getDbClient();
+ private DbSession dbSession = dbTester.getSession();
+
+ private UuidFactory uuidFactory = mock(UuidFactory.class);
+ private ProjectAlmBindingDao underTest = new ProjectAlmBindingDao(system2, uuidFactory);
+
+ @Test
+ public void insert_throws_NPE_if_alm_is_null() {
+ expectAlmNPE();
+
+ underTest.insertOrUpdate(dbSession, null, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_repo_id_is_null() {
+ expectRepoIdNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, null, A_UUID, A_GITHUB_SLUG, A_URL);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_repo_id_is_empty() {
+ expectRepoIdNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, EMPTY_STRING, A_UUID, A_GITHUB_SLUG, A_URL);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_project_uuid_is_null() {
+ expectProjectUuidNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, null, A_GITHUB_SLUG, A_URL);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_project_uuid_is_empty() {
+ expectProjectUuidNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, EMPTY_STRING, A_GITHUB_SLUG, A_URL);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_url_is_null() {
+ expectUrlNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, null);
+ }
+
+ @Test
+ public void insert_throws_IAE_if_url_is_empty() {
+ expectUrlNullOrEmptyIAE();
+
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, EMPTY_STRING);
+ }
+
+ @Test
+ public void insert() {
+ when(system2.now()).thenReturn(DATE);
+ when(uuidFactory.create()).thenReturn("uuid1");
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
+
+ assertThatProjectAlmBinding(GITHUB, A_REPO)
+ .hasProjectUuid(A_UUID)
+ .hasGithubSlug(A_GITHUB_SLUG)
+ .hasUrl(A_URL)
+ .hasCreatedAt(DATE)
+ .hasUpdatedAt(DATE);
+ }
+
+ @Test
+ public void update() {
+ when(system2.now()).thenReturn(DATE);
+ when(uuidFactory.create()).thenReturn("uuid1");
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
+
+ when(system2.now()).thenReturn(DATE_LATER);
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, ANOTHER_UUID, ANOTHER_GITHUB_SLUG, ANOTHER_URL);
+
+ assertThatProjectAlmBinding(GITHUB, A_REPO)
+ .hasProjectUuid(ANOTHER_UUID)
+ .hasGithubSlug(ANOTHER_GITHUB_SLUG)
+ .hasUrl(ANOTHER_URL)
+ .hasCreatedAt(DATE)
+ .hasUpdatedAt(DATE_LATER);
+ }
+
+ @Test
+ public void insert_multiple() {
+ when(system2.now()).thenReturn(DATE);
+ when(uuidFactory.create()).thenReturn("uuid1").thenReturn("uuid2");
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
+ underTest.insertOrUpdate(dbSession, GITHUB, ANOTHER_REPO, ANOTHER_UUID, ANOTHER_GITHUB_SLUG, ANOTHER_URL);
+
+ assertThatProjectAlmBinding(GITHUB, A_REPO)
+ .hasProjectUuid(A_UUID)
+ .hasGithubSlug(A_GITHUB_SLUG)
+ .hasUrl(A_URL)
+ .hasCreatedAt(DATE)
+ .hasUpdatedAt(DATE);
+
+ assertThatProjectAlmBinding(GITHUB, ANOTHER_REPO)
+ .hasProjectUuid(ANOTHER_UUID)
+ .hasGithubSlug(ANOTHER_GITHUB_SLUG)
+ .hasUrl(ANOTHER_URL)
+ .hasCreatedAt(DATE)
+ .hasUpdatedAt(DATE);
+ }
+
+ @Test
+ public void select_by_repo_id() {
+ when(system2.now()).thenReturn(DATE);
+ when(uuidFactory.create())
+ .thenReturn("uuid1")
+ .thenReturn("uuid2")
+ .thenReturn("uuid3");
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
+ underTest.insertOrUpdate(dbSession, GITHUB, ANOTHER_REPO, ANOTHER_UUID, null, ANOTHER_URL);
+ underTest.insertOrUpdate(dbSession, BITBUCKETCLOUD, ANOTHER_REPO, "foo", null, "http://foo");
+
+ assertThat(underTest.selectByRepoId(dbSession, GITHUB, "foo")).isNotPresent();
+
+ Optional<ProjectAlmBindingDto> dto = underTest.selectByRepoId(dbSession, GITHUB, A_REPO);
+ assertThat(dto).isPresent();
+ assertThat(dto.get().getUuid()).isEqualTo("uuid1");
+ assertThat(dto.get().getAlm()).contains(GITHUB);
+ assertThat(dto.get().getRepoId()).isEqualTo(A_REPO);
+ assertThat(dto.get().getProjectUuid()).isEqualTo(A_UUID);
+ assertThat(dto.get().getUrl()).isEqualTo(A_URL);
+ assertThat(dto.get().getGithubSlug()).isEqualTo(A_GITHUB_SLUG);
+ }
+
+ @Test
+ public void select_by_project_uuid() {
+ when(system2.now()).thenReturn(DATE);
+ when(uuidFactory.create())
+ .thenReturn("uuid1")
+ .thenReturn("uuid2")
+ .thenReturn("uuid3");
+ underTest.insertOrUpdate(dbSession, BITBUCKETCLOUD, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
+ underTest.insertOrUpdate(dbSession, BITBUCKETCLOUD, ANOTHER_REPO, ANOTHER_UUID, null, ANOTHER_URL);
+ underTest.insertOrUpdate(dbSession, GITHUB, ANOTHER_REPO, "foo", null, "http://foo");
+
+ assertThat(underTest.selectByProjectUuid(dbSession, "missing")).isNotPresent();
+
+ Optional<ProjectAlmBindingDto> dto = underTest.selectByProjectUuid(dbSession, A_UUID);
+ assertThat(dto).isPresent();
+ assertThat(dto.get().getUuid()).isEqualTo("uuid1");
+ assertThat(dto.get().getAlm()).contains(BITBUCKETCLOUD);
+ assertThat(dto.get().getRepoId()).isEqualTo(A_REPO);
+ assertThat(dto.get().getProjectUuid()).isEqualTo(A_UUID);
+ assertThat(dto.get().getUrl()).isEqualTo(A_URL);
+ assertThat(dto.get().getGithubSlug()).isEqualTo(A_GITHUB_SLUG);
+ }
+
+ @Test
+ public void select_by_repo_ids() {
+ when(system2.now()).thenReturn(DATE);
+ when(uuidFactory.create())
+ .thenReturn("uuid1")
+ .thenReturn("uuid2")
+ .thenReturn("uuid3");
+
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
+ underTest.insertOrUpdate(dbSession, GITHUB, ANOTHER_REPO, ANOTHER_UUID, null, ANOTHER_URL);
+ underTest.insertOrUpdate(dbSession, BITBUCKETCLOUD, ANOTHER_REPO, "foo", null, "http://foo");
+
+ assertThat(underTest.selectByRepoIds(dbSession, GITHUB, Arrays.asList(A_REPO, ANOTHER_REPO, "foo")))
+ .extracting(ProjectAlmBindingDto::getUuid, t -> t.getAlm().get(), ProjectAlmBindingDto::getRepoId, ProjectAlmBindingDto::getProjectUuid,
+ ProjectAlmBindingDto::getUrl, ProjectAlmBindingDto::getGithubSlug)
+ .containsExactlyInAnyOrder(
+ tuple("uuid1", GITHUB, A_REPO, A_UUID, A_URL, A_GITHUB_SLUG),
+ tuple("uuid2", GITHUB, ANOTHER_REPO, ANOTHER_UUID, ANOTHER_URL, null));
+ }
+
+ @Test
+ public void findProjectKey_throws_NPE_when_alm_is_null() {
+ expectAlmNPE();
+
+ underTest.findProjectKey(dbSession, null, A_REPO);
+ }
+
+ @Test
+ public void findProjectKey_throws_IAE_when_repo_id_is_null() {
+ expectRepoIdNullOrEmptyIAE();
+
+ underTest.findProjectKey(dbSession, GITHUB, null);
+ }
+
+ @Test
+ public void findProjectKey_throws_IAE_when_repo_id_is_empty() {
+ expectRepoIdNullOrEmptyIAE();
+
+ underTest.findProjectKey(dbSession, GITHUB, EMPTY_STRING);
+ }
+
+ @Test
+ public void findProjectKey_returns_empty_when_entry_does_not_exist_in_DB() {
+ assertThat(underTest.findProjectKey(dbSession, GITHUB, A_REPO)).isEmpty();
+ }
+
+ @Test
+ public void findProjectKey_returns_projectKey_when_entry_exists() {
+ String projectKey = randomAlphabetic(10);
+ ComponentDto project = createProject(projectKey);
+ when(uuidFactory.create()).thenReturn("uuid1");
+ underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, project.projectUuid(), A_GITHUB_SLUG, A_URL);
+
+ assertThat(underTest.findProjectKey(dbSession, GITHUB, A_REPO)).contains(projectKey);
+ }
+
+ private void expectAlmNPE() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("alm can't be null");
+ }
+
+ private void expectRepoIdNullOrEmptyIAE() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("repoId can't be null nor empty");
+ }
+
+ private void expectProjectUuidNullOrEmptyIAE() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("projectUuid can't be null nor empty");
+ }
+
+ private void expectUrlNullOrEmptyIAE() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("url can't be null nor empty");
+ }
+
+ private ProjectAlmBindingAssert assertThatProjectAlmBinding(ALM alm, String repoId) {
+ return new ProjectAlmBindingAssert(dbTester, dbSession, alm, repoId);
+ }
+
+ private static class ProjectAlmBindingAssert extends AbstractAssert<ProjectAlmBindingAssert, ProjectAlmBinding> {
+
+ private ProjectAlmBindingAssert(DbTester dbTester, DbSession dbSession, ALM alm, String repoId) {
+ super(asProjectAlmBinding(dbTester, dbSession, alm, repoId), ProjectAlmBindingAssert.class);
+ }
+
+ private static ProjectAlmBinding asProjectAlmBinding(DbTester dbTester, DbSession dbSession, ALM alm, String repoId) {
+ List<Map<String, Object>> rows = dbTester.select(
+ dbSession,
+ "select" +
+ " project_uuid as \"projectUuid\", github_slug as \"githubSlug\", url as \"url\", " +
+ " created_at as \"createdAt\", updated_at as \"updatedAt\"" +
+ " from project_alm_bindings" +
+ " where alm_id='" + alm.getId() + "' and repo_id='" + repoId + "'");
+ if (rows.isEmpty()) {
+ return null;
+ }
+ if (rows.size() > 1) {
+ throw new IllegalStateException("Unique index violation");
+ }
+ return new ProjectAlmBinding(
+ (String) rows.get(0).get("projectUuid"),
+ (String) rows.get(0).get("githubSlug"),
+ (String) rows.get(0).get("url"),
+ (Long) rows.get(0).get("createdAt"),
+ (Long) rows.get(0).get("updatedAt"));
+ }
+
+ public void doesNotExist() {
+ isNull();
+ }
+
+ ProjectAlmBindingAssert hasProjectUuid(String expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.projectUuid, expected)) {
+ failWithMessage("Expected Project ALM Binding to have column PROJECT_UUID to be <%s> but was <%s>", expected, actual.projectUuid);
+ }
+ return this;
+ }
+
+ ProjectAlmBindingAssert hasGithubSlug(String expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.githubSlug, expected)) {
+ failWithMessage("Expected Project ALM Binding to have column GITHUB_SLUG to be <%s> but was <%s>", expected, actual.githubSlug);
+ }
+ return this;
+ }
+
+ ProjectAlmBindingAssert hasUrl(String expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.url, expected)) {
+ failWithMessage("Expected Project ALM Binding to have column URL to be <%s> but was <%s>", expected, actual.url);
+ }
+ return this;
+ }
+
+ ProjectAlmBindingAssert hasCreatedAt(long expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.createdAt, expected)) {
+ failWithMessage("Expected Project ALM Binding to have column CREATED_AT to be <%s> but was <%s>", expected, actual.createdAt);
+ }
+
+ return this;
+ }
+
+ ProjectAlmBindingAssert hasUpdatedAt(long expected) {
+ isNotNull();
+
+ if (!Objects.equals(actual.updatedAt, expected)) {
+ failWithMessage("Expected Project ALM Binding to have column UPDATED_AT to be <%s> but was <%s>", expected, actual.updatedAt);
+ }
+
+ return this;
+ }
+
+ }
+
+ private static final class ProjectAlmBinding {
+ private final String projectUuid;
+ private final String githubSlug;
+ private final String url;
+ private final Long createdAt;
+ private final Long updatedAt;
+
+ ProjectAlmBinding(@Nullable String projectUuid, @Nullable String githubSlug, @Nullable String url, @Nullable Long createdAt, @Nullable Long updatedAt) {
+ this.projectUuid = projectUuid;
+ this.githubSlug = githubSlug;
+ this.url = url;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ }
+ }
+
+ private ComponentDto createProject(String projectKey) {
+ ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert()).setDbKey(projectKey);
+ dbClient.componentDao().insert(dbSession, project);
+ dbSession.commit();
+ return project;
+ }
+}
+++ /dev/null
-/*
- * 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;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import javax.annotation.Nullable;
-import org.assertj.core.api.AbstractAssert;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.System2;
-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.component.ComponentDto;
-import org.sonar.db.component.ComponentTesting;
-
-import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.tuple;
-import static org.mockito.Mockito.mock;
-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 {
-
- private static final String A_UUID = "abcde1234";
- private static final String ANOTHER_UUID = "xyz789";
- private static final String EMPTY_STRING = "";
-
- private static final String A_REPO = "my_repo";
- private static final String ANOTHER_REPO = "another_repo";
-
- private static final String A_GITHUB_SLUG = null;
- private static final String ANOTHER_GITHUB_SLUG = "example/foo";
-
- private static final String A_URL = "foo url";
- private static final String ANOTHER_URL = "bar url";
-
- private static final long DATE = 1_600_000_000_000L;
- private static final long DATE_LATER = 1_700_000_000_000L;
-
- private System2 system2 = mock(System2.class);
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
- @Rule
- public DbTester dbTester = DbTester.create(system2);
- private DbClient dbClient = dbTester.getDbClient();
- private DbSession dbSession = dbTester.getSession();
-
- private UuidFactory uuidFactory = mock(UuidFactory.class);
- private ProjectAlmBindingsDao underTest = new ProjectAlmBindingsDao(system2, uuidFactory);
-
- @Test
- public void insert_throws_NPE_if_alm_is_null() {
- expectAlmNPE();
-
- underTest.insertOrUpdate(dbSession, null, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
- }
-
- @Test
- public void insert_throws_IAE_if_repo_id_is_null() {
- expectRepoIdNullOrEmptyIAE();
-
- underTest.insertOrUpdate(dbSession, GITHUB, null, A_UUID, A_GITHUB_SLUG, A_URL);
- }
-
- @Test
- public void insert_throws_IAE_if_repo_id_is_empty() {
- expectRepoIdNullOrEmptyIAE();
-
- underTest.insertOrUpdate(dbSession, GITHUB, EMPTY_STRING, A_UUID, A_GITHUB_SLUG, A_URL);
- }
-
- @Test
- public void insert_throws_IAE_if_project_uuid_is_null() {
- expectProjectUuidNullOrEmptyIAE();
-
- underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, null, A_GITHUB_SLUG, A_URL);
- }
-
- @Test
- public void insert_throws_IAE_if_project_uuid_is_empty() {
- expectProjectUuidNullOrEmptyIAE();
-
- underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, EMPTY_STRING, A_GITHUB_SLUG, A_URL);
- }
-
- @Test
- public void insert_throws_IAE_if_url_is_null() {
- expectUrlNullOrEmptyIAE();
-
- underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, null);
- }
-
- @Test
- public void insert_throws_IAE_if_url_is_empty() {
- expectUrlNullOrEmptyIAE();
-
- underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, EMPTY_STRING);
- }
-
- @Test
- public void insert() {
- when(system2.now()).thenReturn(DATE);
- when(uuidFactory.create()).thenReturn("uuid1");
- underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
-
- assertThatProjectAlmBinding(GITHUB, A_REPO)
- .hasProjectUuid(A_UUID)
- .hasGithubSlug(A_GITHUB_SLUG)
- .hasUrl(A_URL)
- .hasCreatedAt(DATE)
- .hasUpdatedAt(DATE);
- }
-
- @Test
- public void update() {
- when(system2.now()).thenReturn(DATE);
- when(uuidFactory.create()).thenReturn("uuid1");
- underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
-
- when(system2.now()).thenReturn(DATE_LATER);
- underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, ANOTHER_UUID, ANOTHER_GITHUB_SLUG, ANOTHER_URL);
-
- assertThatProjectAlmBinding(GITHUB, A_REPO)
- .hasProjectUuid(ANOTHER_UUID)
- .hasGithubSlug(ANOTHER_GITHUB_SLUG)
- .hasUrl(ANOTHER_URL)
- .hasCreatedAt(DATE)
- .hasUpdatedAt(DATE_LATER);
- }
-
- @Test
- public void insert_multiple() {
- when(system2.now()).thenReturn(DATE);
- when(uuidFactory.create()).thenReturn("uuid1").thenReturn("uuid2");
- underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
- underTest.insertOrUpdate(dbSession, GITHUB, ANOTHER_REPO, ANOTHER_UUID, ANOTHER_GITHUB_SLUG, ANOTHER_URL);
-
- assertThatProjectAlmBinding(GITHUB, A_REPO)
- .hasProjectUuid(A_UUID)
- .hasGithubSlug(A_GITHUB_SLUG)
- .hasUrl(A_URL)
- .hasCreatedAt(DATE)
- .hasUpdatedAt(DATE);
-
- assertThatProjectAlmBinding(GITHUB, ANOTHER_REPO)
- .hasProjectUuid(ANOTHER_UUID)
- .hasGithubSlug(ANOTHER_GITHUB_SLUG)
- .hasUrl(ANOTHER_URL)
- .hasCreatedAt(DATE)
- .hasUpdatedAt(DATE);
- }
-
- @Test
- public void select_by_repo_id() {
- when(system2.now()).thenReturn(DATE);
- when(uuidFactory.create())
- .thenReturn("uuid1")
- .thenReturn("uuid2")
- .thenReturn("uuid3");
- underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
- underTest.insertOrUpdate(dbSession, GITHUB, ANOTHER_REPO, ANOTHER_UUID, null, ANOTHER_URL);
- underTest.insertOrUpdate(dbSession, BITBUCKETCLOUD, ANOTHER_REPO, "foo", null, "http://foo");
-
- assertThat(underTest.selectByRepoId(dbSession, GITHUB, "foo")).isNotPresent();
-
- Optional<ProjectAlmBindingDto> dto = underTest.selectByRepoId(dbSession, GITHUB, A_REPO);
- assertThat(dto).isPresent();
- assertThat(dto.get().getUuid()).isEqualTo("uuid1");
- assertThat(dto.get().getAlm()).contains(GITHUB);
- assertThat(dto.get().getRepoId()).isEqualTo(A_REPO);
- assertThat(dto.get().getProjectUuid()).isEqualTo(A_UUID);
- assertThat(dto.get().getUrl()).isEqualTo(A_URL);
- assertThat(dto.get().getGithubSlug()).isEqualTo(A_GITHUB_SLUG);
- }
-
- @Test
- public void select_by_project_uuid() {
- when(system2.now()).thenReturn(DATE);
- when(uuidFactory.create())
- .thenReturn("uuid1")
- .thenReturn("uuid2")
- .thenReturn("uuid3");
- underTest.insertOrUpdate(dbSession, BITBUCKETCLOUD, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
- underTest.insertOrUpdate(dbSession, BITBUCKETCLOUD, ANOTHER_REPO, ANOTHER_UUID, null, ANOTHER_URL);
- underTest.insertOrUpdate(dbSession, GITHUB, ANOTHER_REPO, "foo", null, "http://foo");
-
- assertThat(underTest.selectByProjectUuid(dbSession, "missing")).isNotPresent();
-
- Optional<ProjectAlmBindingDto> dto = underTest.selectByProjectUuid(dbSession, A_UUID);
- assertThat(dto).isPresent();
- assertThat(dto.get().getUuid()).isEqualTo("uuid1");
- assertThat(dto.get().getAlm()).contains(BITBUCKETCLOUD);
- assertThat(dto.get().getRepoId()).isEqualTo(A_REPO);
- assertThat(dto.get().getProjectUuid()).isEqualTo(A_UUID);
- assertThat(dto.get().getUrl()).isEqualTo(A_URL);
- assertThat(dto.get().getGithubSlug()).isEqualTo(A_GITHUB_SLUG);
- }
-
- @Test
- public void select_by_repo_ids() {
- when(system2.now()).thenReturn(DATE);
- when(uuidFactory.create())
- .thenReturn("uuid1")
- .thenReturn("uuid2")
- .thenReturn("uuid3");
-
- underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, A_UUID, A_GITHUB_SLUG, A_URL);
- underTest.insertOrUpdate(dbSession, GITHUB, ANOTHER_REPO, ANOTHER_UUID, null, ANOTHER_URL);
- underTest.insertOrUpdate(dbSession, BITBUCKETCLOUD, ANOTHER_REPO, "foo", null, "http://foo");
-
- assertThat(underTest.selectByRepoIds(dbSession, GITHUB, Arrays.asList(A_REPO, ANOTHER_REPO, "foo")))
- .extracting(ProjectAlmBindingDto::getUuid, t -> t.getAlm().get(), ProjectAlmBindingDto::getRepoId, ProjectAlmBindingDto::getProjectUuid,
- ProjectAlmBindingDto::getUrl, ProjectAlmBindingDto::getGithubSlug)
- .containsExactlyInAnyOrder(
- tuple("uuid1", GITHUB, A_REPO, A_UUID, A_URL, A_GITHUB_SLUG),
- tuple("uuid2", GITHUB, ANOTHER_REPO, ANOTHER_UUID, ANOTHER_URL, null));
- }
-
- @Test
- public void findProjectKey_throws_NPE_when_alm_is_null() {
- expectAlmNPE();
-
- underTest.findProjectKey(dbSession, null, A_REPO);
- }
-
- @Test
- public void findProjectKey_throws_IAE_when_repo_id_is_null() {
- expectRepoIdNullOrEmptyIAE();
-
- underTest.findProjectKey(dbSession, GITHUB, null);
- }
-
- @Test
- public void findProjectKey_throws_IAE_when_repo_id_is_empty() {
- expectRepoIdNullOrEmptyIAE();
-
- underTest.findProjectKey(dbSession, GITHUB, EMPTY_STRING);
- }
-
- @Test
- public void findProjectKey_returns_empty_when_entry_does_not_exist_in_DB() {
- assertThat(underTest.findProjectKey(dbSession, GITHUB, A_REPO)).isEmpty();
- }
-
- @Test
- public void findProjectKey_returns_projectKey_when_entry_exists() {
- String projectKey = randomAlphabetic(10);
- ComponentDto project = createProject(projectKey);
- when(uuidFactory.create()).thenReturn("uuid1");
- underTest.insertOrUpdate(dbSession, GITHUB, A_REPO, project.projectUuid(), A_GITHUB_SLUG, A_URL);
-
- assertThat(underTest.findProjectKey(dbSession, GITHUB, A_REPO)).contains(projectKey);
- }
-
- private void expectAlmNPE() {
- expectedException.expect(NullPointerException.class);
- expectedException.expectMessage("alm can't be null");
- }
-
- private void expectRepoIdNullOrEmptyIAE() {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("repoId can't be null nor empty");
- }
-
- private void expectProjectUuidNullOrEmptyIAE() {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("projectUuid can't be null nor empty");
- }
-
- private void expectUrlNullOrEmptyIAE() {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("url can't be null nor empty");
- }
-
- private ProjectAlmBindingAssert assertThatProjectAlmBinding(ALM alm, String repoId) {
- return new ProjectAlmBindingAssert(dbTester, dbSession, alm, repoId);
- }
-
- private static class ProjectAlmBindingAssert extends AbstractAssert<ProjectAlmBindingAssert, ProjectAlmBinding> {
-
- private ProjectAlmBindingAssert(DbTester dbTester, DbSession dbSession, ALM alm, String repoId) {
- super(asProjectAlmBinding(dbTester, dbSession, alm, repoId), ProjectAlmBindingAssert.class);
- }
-
- private static ProjectAlmBinding asProjectAlmBinding(DbTester dbTester, DbSession dbSession, ALM alm, String repoId) {
- List<Map<String, Object>> rows = dbTester.select(
- dbSession,
- "select" +
- " project_uuid as \"projectUuid\", github_slug as \"githubSlug\", url as \"url\", " +
- " created_at as \"createdAt\", updated_at as \"updatedAt\"" +
- " from project_alm_bindings" +
- " where alm_id='" + alm.getId() + "' and repo_id='" + repoId + "'");
- if (rows.isEmpty()) {
- return null;
- }
- if (rows.size() > 1) {
- throw new IllegalStateException("Unique index violation");
- }
- return new ProjectAlmBinding(
- (String) rows.get(0).get("projectUuid"),
- (String) rows.get(0).get("githubSlug"),
- (String) rows.get(0).get("url"),
- (Long) rows.get(0).get("createdAt"),
- (Long) rows.get(0).get("updatedAt"));
- }
-
- public void doesNotExist() {
- isNull();
- }
-
- ProjectAlmBindingAssert hasProjectUuid(String expected) {
- isNotNull();
-
- if (!Objects.equals(actual.projectUuid, expected)) {
- failWithMessage("Expected Project ALM Binding to have column PROJECT_UUID to be <%s> but was <%s>", expected, actual.projectUuid);
- }
- return this;
- }
-
- ProjectAlmBindingAssert hasGithubSlug(String expected) {
- isNotNull();
-
- if (!Objects.equals(actual.githubSlug, expected)) {
- failWithMessage("Expected Project ALM Binding to have column GITHUB_SLUG to be <%s> but was <%s>", expected, actual.githubSlug);
- }
- return this;
- }
-
- ProjectAlmBindingAssert hasUrl(String expected) {
- isNotNull();
-
- if (!Objects.equals(actual.url, expected)) {
- failWithMessage("Expected Project ALM Binding to have column URL to be <%s> but was <%s>", expected, actual.url);
- }
- return this;
- }
-
- ProjectAlmBindingAssert hasCreatedAt(long expected) {
- isNotNull();
-
- if (!Objects.equals(actual.createdAt, expected)) {
- failWithMessage("Expected Project ALM Binding to have column CREATED_AT to be <%s> but was <%s>", expected, actual.createdAt);
- }
-
- return this;
- }
-
- ProjectAlmBindingAssert hasUpdatedAt(long expected) {
- isNotNull();
-
- if (!Objects.equals(actual.updatedAt, expected)) {
- failWithMessage("Expected Project ALM Binding to have column UPDATED_AT to be <%s> but was <%s>", expected, actual.updatedAt);
- }
-
- return this;
- }
-
- }
-
- private static final class ProjectAlmBinding {
- private final String projectUuid;
- private final String githubSlug;
- private final String url;
- private final Long createdAt;
- private final Long updatedAt;
-
- ProjectAlmBinding(@Nullable String projectUuid, @Nullable String githubSlug, @Nullable String url, @Nullable Long createdAt, @Nullable Long updatedAt) {
- this.projectUuid = projectUuid;
- this.githubSlug = githubSlug;
- this.url = url;
- this.createdAt = createdAt;
- this.updatedAt = updatedAt;
- }
- }
-
- private ComponentDto createProject(String projectKey) {
- ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert()).setDbKey(projectKey);
- dbClient.componentDao().insert(dbSession, project);
- dbSession.commit();
- return project;
- }
-}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
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)
;
}
}
--- /dev/null
+/*
+ * 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");
+ }
+
+}
@Test
public void verify_migration_count() {
- verifyMigrationCount(underTest, 1);
+ verifyMigrationCount(underTest, 2);
}
}
--- /dev/null
+/*
+ * 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);
+}
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;
* @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.
}
@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)) {
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
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;
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;
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;
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;
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
.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)
"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);
}
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,
.setDescription(description)
.setUrl(url)
.setAvatarUrl(avatar)
- .build());
+ .build(),
+ o -> bindOrganization(request, dbSession, o));
writeResponse(request, response, organization);
} catch (OrganizationUpdater.KeyConflictException e) {
}
}
+ 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);
deleteGroups(dbSession, organization);
deleteQualityProfiles(dbSession, organization);
deleteQualityGates(dbSession, organization);
+ deleteOrganizationAlmBinding(dbSession, organization);
deleteOrganization(dbSession, organization);
billingValidations.onDelete(new BillingValidations.Organization(organization.getKey(), organization.getUuid()));
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) {
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());
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;
}
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())
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;
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;
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
@Override
public void handle(Request request, Response response) throws Exception {
boolean isMember = request.mandatoryParamAsBoolean(PARAM_MEMBER);
- if (isMember){
+ if (isMember) {
userSession.checkLoggedIn();
}
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);
}
}
: 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))
.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();
});
}
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;
private System2 system2 = new TestSystem2().setNow(A_DATE);
+ private static Consumer<OrganizationDto> EMPTY_ORGANIZATION_CONSUMER = o -> {
+ };
+
@Rule
public DbTester db = DbTester.create(system2);
@Rule
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();
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());
}
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());
}
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");
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();
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);
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);
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
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);
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
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;
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;
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() {
assertThat(organization.getName()).isEqualTo("a");
}
+ @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();
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"))
.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
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;
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;
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[][] {
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;
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;
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;
@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
.doesNotContain(organizationWithoutMember.getKey());
}
+ @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();
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
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
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() {
+++ /dev/null
-{
- "organization": "my-org",
- "key": "polop",
- "id": "xyz",
- "branch": "feature1",
- "name": "Polop",
- "description": "test project",
- "almId": "bitbucketcloud",
- "almRepoUrl": "http://bitbucket.org/foo/bar"
-}
+++ /dev/null
-{
- "organization": "my-org",
- "key": "palap",
- "id": "bcde",
- "name": "Palap",
- "almId": "bitbucketcloud",
- "almRepoUrl": "http://bitbucket.org/foo/bar"
-}
+++ /dev/null
-{
- "organization": "my-org",
- "key": "polop",
- "id": "abcd",
- "name": "Polop",
- "description": "test project",
- "almId": "bitbucketcloud",
- "almRepoUrl": "http://bitbucket.org/foo/bar"
-}
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 {