"plugins",
"portfolios",
"portfolio_projects",
+ "portfolio_proj_branches",
"portfolio_references",
"projects",
"project_alm_settings",
confBuilder.loadAlias("Portfolio", PortfolioDto.class);
confBuilder.loadAlias("PortfolioProject", PortfolioProjectDto.class);
confBuilder.loadAlias("PortfolioReference", PortfolioReferenceDto.class);
-
confBuilder.loadAlias("PrIssue", PrIssueDto.class);
confBuilder.loadAlias("ProjectQgateAssociation", ProjectQgateAssociationDto.class);
confBuilder.loadAlias("Project", ProjectDto.class);
*/
package org.sonar.db.portfolio;
-import java.util.Collection;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
import java.util.Set;
-import java.util.stream.Collectors;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.utils.System2;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbSession;
import org.sonar.db.audit.AuditPersister;
import org.sonar.db.audit.model.ComponentNewValue;
-import org.sonar.db.project.ProjectDto;
import static com.google.common.base.Preconditions.checkArgument;
+import static java.lang.String.format;
import static java.util.Collections.emptyList;
import static java.util.Collections.singleton;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;
this.auditPersister = auditPersister;
}
+ /*
+ * Select portfolios
+ */
public List<PortfolioDto> selectAllRoots(DbSession dbSession) {
return mapper(dbSession).selectAllRoots();
}
return mapper(dbSession).selectByUuids(uuids);
}
+ /*
+ * Modify portfolios
+ */
public void insert(DbSession dbSession, PortfolioDto portfolio) {
checkArgument(portfolio.isRoot() == (portfolio.getUuid().equals(portfolio.getRootUuid())));
mapper(dbSession).insert(portfolio);
auditPersister.updateComponent(dbSession, toComponentNewValue(portfolio));
}
- private static ComponentNewValue toComponentNewValue(PortfolioDto portfolio) {
- return new ComponentNewValue(portfolio.getUuid(), portfolio.getName(), portfolio.getKey(), portfolio.isPrivate(),
- portfolio.getDescription(), qualifier(portfolio));
- }
-
- private static String qualifier(PortfolioDto portfolioDto) {
- return portfolioDto.isRoot() ? Qualifiers.VIEW : Qualifiers.SUBVIEW;
- }
-
- public Map<String, String> selectKeysByUuids(DbSession dbSession, Collection<String> uuids) {
- return executeLargeInputs(uuids, uuids1 -> mapper(dbSession).selectByUuids(uuids1)).stream()
- .collect(Collectors.toMap(PortfolioDto::getUuid, PortfolioDto::getKey));
- }
-
+ /*
+ * Portfolio references
+ */
public void addReference(DbSession dbSession, String portfolioUuid, String referenceUuid) {
mapper(dbSession).insertReference(new PortfolioReferenceDto()
.setUuid(uuidFactory.create())
return mapper(dbSession).selectReference(portfolioUuid, referenceKey);
}
- public List<ProjectDto> selectProjects(DbSession dbSession, String portfolioUuid) {
- return mapper(dbSession).selectProjects(portfolioUuid);
+ /*
+ * Manual selection of projects
+ */
+ public List<PortfolioProjectDto> selectPortfolioProjects(DbSession dbSession, String portfolioUuid) {
+ return mapper(dbSession).selectPortfolioProjects(portfolioUuid);
}
public List<PortfolioProjectDto> selectAllProjectsInHierarchy(DbSession dbSession, String rootUuid) {
return mapper(dbSession).selectAllPortfolioProjects();
}
- public void addProject(DbSession dbSession, String portfolioUuid, String projectUuid) {
- mapper(dbSession).insertProject(new PortfolioProjectDto()
- .setUuid(uuidFactory.create())
- .setPortfolioUuid(portfolioUuid)
- .setProjectUuid(projectUuid)
- .setCreatedAt(system2.now()));
+ public PortfolioProjectDto selectPortfolioProjectOrFail(DbSession dbSession, String portfolioUuid, String projectUuid) {
+ return Optional.ofNullable(mapper(dbSession).selectPortfolioProject(portfolioUuid, projectUuid)).orElseThrow(() ->
+ new IllegalArgumentException(format("Project '%s' not selected in portfolio '%s'", projectUuid, portfolioUuid)));
+ }
+
+ public String addProject(DbSession dbSession, String portfolioUuid, String projectUuid) {
+ String uuid = uuidFactory.create();
+ mapper(dbSession).insertProject(uuid, portfolioUuid, projectUuid, system2.now());
+ return uuid;
}
public void deleteProjects(DbSession dbSession, String portfolioUuid) {
mapper(dbSession).deleteAllProjects();
}
+ public Set<String> selectBranches(DbSession dbSession, String portfolioProjectUuid) {
+ return mapper(dbSession).selectBranches(portfolioProjectUuid);
+ }
+
+ public void addBranch(DbSession dbSession, String portfolioProjectUuid, String branchKey) {
+ mapper(dbSession).insertBranch(uuidFactory.create(), portfolioProjectUuid, branchKey, system2.now());
+ }
+
+ public void deleteBranch(DbSession dbSession, String portfolioUuid, String projectUuid, String branchKey) {
+ mapper(dbSession).deleteBranch(portfolioUuid, projectUuid, branchKey);
+ }
+
+ /*
+ * Utils
+ */
private static PortfolioMapper mapper(DbSession session) {
return session.getMapper(PortfolioMapper.class);
}
+ private static ComponentNewValue toComponentNewValue(PortfolioDto portfolio) {
+ return new ComponentNewValue(portfolio.getUuid(), portfolio.isPrivate(), portfolio.getName(), portfolio.getKey(), portfolio.getDescription(), qualifier(portfolio));
+ }
+
+ private static String qualifier(PortfolioDto portfolioDto) {
+ return portfolioDto.isRoot() ? Qualifiers.VIEW : Qualifiers.SUBVIEW;
+ }
}
private String name;
private String description;
private boolean isPrivate = false;
+ private String branchName;
private String rootUuid;
private String parentUuid;
return this;
}
+ @CheckForNull
+ public String getBranchName() {
+ return branchName;
+ }
+
+ public void setBranchName(@Nullable String branchName) {
+ this.branchName = branchName;
+ }
+
public String getSelectionMode() {
return selectionMode;
}
import java.util.Set;
import javax.annotation.CheckForNull;
import org.apache.ibatis.annotations.Param;
-import org.sonar.db.project.ProjectDto;
public interface PortfolioMapper {
@CheckForNull
PortfolioDto selectByKey(String key);
- List<PortfolioDto> selectByKeys(@Param("keys")List<String> keys);
+ List<PortfolioDto> selectByKeys(@Param("keys") List<String> keys);
@CheckForNull
PortfolioDto selectByUuid(String uuid);
void insertReference(PortfolioReferenceDto portfolioReference);
- void insertProject(PortfolioProjectDto portfolioProject);
+ void insertProject(@Param("uuid") String uuid, @Param("portfolioUuid") String portfolioUuid, @Param("projectUuid") String projectUuid, @Param("createdAt") long createdAt);
List<PortfolioDto> selectTree(String portfolioUuid);
List<PortfolioDto> selectReferencers(String referenceUuid);
- List<ProjectDto> selectProjects(String portfolioUuid);
+ List<PortfolioProjectDto> selectPortfolioProjects(String portfolioUuid);
+
+ PortfolioProjectDto selectPortfolioProject(@Param("portfolioUuid") String portfolioUuid, @Param("projectUuid") String projectUuid);
List<ReferenceDto> selectAllReferencesToPortfolios();
List<ReferenceDto> selectAllReferencesInHierarchy(String rootUuid);
+ void deleteBranch(@Param("portfolioProjectUuid") String portfolioProjectUuid, @Param("branchKey") String branchKey);
+
+ void deleteBranch(@Param("portfolioUuid") String portfolioUuid, @Param("projectUuid") String projectUuid, @Param("branchKey") String branchKey);
+
+ void insertBranch(@Param("uuid") String uuid, @Param("portfolioProjectUuid") String portfolioProjectUuid, @Param("branchKey") String branchKey,
+ @Param("createdAt") long createdAt);
+ Set<String> selectBranches(String portfolioProjectUuid);
}
*/
package org.sonar.db.portfolio;
+import java.util.Set;
+
public class PortfolioProjectDto {
private String uuid;
private String portfolioUuid;
+ private String portfolioKey;
private String projectUuid;
+ private String projectKey;
+ private Set<String> branchKeys;
private long createdAt;
public String getUuid() {
this.createdAt = createdAt;
return this;
}
+
+ public String getPortfolioKey() {
+ return portfolioKey;
+ }
+
+ public PortfolioProjectDto setPortfolioKey(String portfolioKey) {
+ this.portfolioKey = portfolioKey;
+ return this;
+ }
+
+ public String getProjectKey() {
+ return projectKey;
+ }
+
+ public PortfolioProjectDto setProjectKey(String projectKey) {
+ this.projectKey = projectKey;
+ return this;
+ }
+
+ public Set<String> getBranchKeys() {
+ return branchKeys;
+ }
+
+ public void setBranchKeys(Set<String> branchKeys) {
+ this.branchKeys = branchKeys;
+ }
}
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd">
<mapper namespace="org.sonar.db.portfolio.PortfolioMapper">
- <sql id="portfolioColumns">
- p.uuid as uuid,
- p.kee as kee,
- p.name as name,
- p.description as description,
- p.private as isPrivate,
- p.root_uuid as rootUuid,
- p.parent_uuid as parentUuid,
- p.selection_mode as selectionMode,
- p.selection_expression as selectionExpression,
- p.created_at as createdAt,
- p.updated_at as updatedAt
- </sql>
+ <sql id="portfolioColumns">
+ p.uuid as uuid,
+ p.kee as kee,
+ p.name as name,
+ p.description as description,
+ p.private as isPrivate,
+ p.branch_name as branchName,
+ p.root_uuid as rootUuid,
+ p.parent_uuid as parentUuid,
+ p.selection_mode as selectionMode,
+ p.selection_expression as selectionExpression,
+ p.created_at as createdAt,
+ p.updated_at as updatedAt
+ </sql>
<sql id="projectColumns">
p.uuid as uuid,
p.updated_at as updatedAt
</sql>
+ <sql id="portfolioProjectColumns">
+ pp.uuid as portfolioProject_uuid,
+ pp.project_uuid as projectUuid,
+ pp.portfolio_uuid as portfolioUuid,
+ pf.kee as portfolioKey,
+ pp.project_uuid as projectUuid,
+ p.kee as projectKey,
+ pp.created_at as createdAt,
+ ppb.branch_key as branchKey
+ </sql>
+
+ <resultMap id="portfolioProjectResult" type="PortfolioProject" autoMapping="true">
+ <id property="uuid" column="portfolioProject_uuid" />
+ <collection property="branchKeys" ofType="string">
+ <result column="branchKey" />
+ </collection>
+ </resultMap>
+
<select id="selectByUuid" parameterType="String" resultType="Portfolio">
SELECT
<include refid="portfolioColumns"/>
p.parent_uuid is null
</select>
- <select id="selectProjects" resultType="Project">
+ <select id="selectPortfolioProjectBranches" resultType="string">
+ SELECT ppb.branch_key
+ FROM portfolio_proj_branches ppb
+ WHERE ppb.portfolio_project_uuid = #{id}
+ </select>
+
+ <select id="selectPortfolioProjects" resultMap="portfolioProjectResult">
SELECT
- <include refid="projectColumns"/>
+ <include refid="portfolioProjectColumns"/>
FROM portfolio_projects pp
INNER JOIN projects p on p.uuid = pp.project_uuid
+ INNER JOIN portfolios pf on pf.uuid = pp.portfolio_uuid
+ LEFT OUTER JOIN portfolio_proj_branches ppb on pp.uuid = ppb.portfolio_project_uuid
WHERE
pp.portfolio_uuid=#{portfolioUuid,jdbcType=VARCHAR}
</select>
- <select id="selectAllPortfolioProjects" resultType="org.sonar.db.portfolio.PortfolioProjectDto">
+ <select id="selectPortfolioProject" resultMap="portfolioProjectResult">
+ SELECT
+ <include refid="portfolioProjectColumns"/>
+ FROM portfolio_projects pp
+ INNER JOIN projects p on p.uuid = pp.project_uuid
+ INNER JOIN portfolios pf on pf.uuid = pp.portfolio_uuid
+ LEFT OUTER JOIN portfolio_proj_branches ppb on pp.uuid = ppb.portfolio_project_uuid
+ WHERE
+ pp.portfolio_uuid=#{portfolioUuid,jdbcType=VARCHAR}
+ and pp.project_uuid=#{projectUuid,jdbcType=VARCHAR}
+
+ </select>
+
+ <select id="selectAllPortfolioProjects" resultMap="portfolioProjectResult">
SELECT
- pp.uuid,
- pp.project_uuid as projectUuid,
- pp.portfolio_uuid as portfolioUuid,
- pp.project_uuid as projectUuid,
- pp.created_at as createdAt
+ <include refid="portfolioProjectColumns"/>
FROM portfolio_projects pp
INNER JOIN projects p on p.uuid = pp.project_uuid
+ INNER JOIN portfolios pf on pf.uuid = pp.portfolio_uuid
+ LEFT OUTER JOIN portfolio_proj_branches ppb on pp.uuid = ppb.portfolio_project_uuid
</select>
- <select id="selectAllProjectsInHierarchy" resultType="org.sonar.db.portfolio.PortfolioProjectDto">
+ <select id="selectAllProjectsInHierarchy" resultMap="portfolioProjectResult">
SELECT
- pp.uuid,
- pp.project_uuid as projectUuid,
- pp.portfolio_uuid as portfolioUuid,
- pp.project_uuid as projectUuid,
- pp.created_at as createdAt
+ <include refid="portfolioProjectColumns"/>
FROM portfolio_projects pp
- INNER JOIN portfolios p
- ON pp.portfolio_uuid = p.uuid
+ INNER JOIN projects p on p.uuid = pp.project_uuid
+ INNER JOIN portfolios pf on pp.portfolio_uuid = pf.uuid
+ LEFT OUTER JOIN portfolio_proj_branches ppb on pp.uuid = ppb.portfolio_project_uuid
where
- p.root_uuid = #{rootUuid,jdbcType=VARCHAR}
+ pf.root_uuid = #{rootUuid,jdbcType=VARCHAR}
</select>
<select id="selectReferenceUuids" resultType="String">
private,
root_uuid,
parent_uuid,
+ branch_name,
selection_mode,
selection_expression,
created_at,
#{isPrivate,jdbcType=BOOLEAN},
#{rootUuid,jdbcType=VARCHAR},
#{parentUuid,jdbcType=VARCHAR},
+ #{branchName,jdbcType=VARCHAR},
#{selectionMode,jdbcType=VARCHAR},
#{selectionExpression,jdbcType=VARCHAR},
#{createdAt,jdbcType=BIGINT},
</delete>
<delete id="deleteProjectsByPortfolioUuids" parameterType="String">
+ delete from portfolio_proj_branches
+ where portfolio_project_uuid in
+ (select uuid from portfolio_projects
+ where portfolio_uuid in
+ <foreach collection="uuids" open="(" close=")" item="uuid" separator=",">#{uuid,jdbcType=VARCHAR}</foreach>);
+
DELETE FROM portfolio_projects WHERE portfolio_uuid in
<foreach collection="uuids" open="(" close=")" item="uuid" separator=",">#{uuid,jdbcType=VARCHAR}</foreach>
</delete>
</delete>
<delete id="deleteAllProjects" parameterType="String">
- DELETE FROM portfolio_projects
+ DELETE FROM portfolio_projects;
+ DELETE FROM portfolio_proj_branches
</delete>
<insert id="insertReference" parameterType="PortfolioReference">
</delete>
<delete id="deleteProjects" parameterType="String">
+ delete from portfolio_proj_branches
+ where portfolio_project_uuid =
+ (select uuid from portfolio_projects
+ where portfolio_uuid = #{portfolioUuid,jdbcType=VARCHAR});
+
delete from portfolio_projects
where portfolio_uuid = #{portfolioUuid,jdbcType=VARCHAR}
</delete>
- <delete id="deleteProject" parameterType="map">
+ <delete id="deleteProject" parameterType="map">
+ delete from portfolio_proj_branches
+ where portfolio_project_uuid =
+ (select uuid from portfolio_projects
+ where portfolio_uuid = #{portfolioUuid,jdbcType=VARCHAR}
+ and project_uuid = #{projectUuid,jdbcType=VARCHAR});
+
delete from portfolio_projects
where portfolio_uuid = #{portfolioUuid,jdbcType=VARCHAR}
- and
- project_uuid = #{projectUuid,jdbcType=VARCHAR}
+ and project_uuid = #{projectUuid,jdbcType=VARCHAR}
</delete>
- <insert id="insertProject" parameterType="PortfolioProject">
+ <insert id="insertProject" parameterType="map">
INSERT INTO portfolio_projects (
uuid,
portfolio_uuid,
)
</insert>
+ <insert id="insertBranch" parameterType="map">
+ INSERT INTO portfolio_proj_branches (
+ uuid,
+ portfolio_project_uuid,
+ branch_key,
+ created_at
+ )
+ VALUES (
+ #{uuid,jdbcType=VARCHAR},
+ #{portfolioProjectUuid,jdbcType=VARCHAR},
+ #{branchKey,jdbcType=VARCHAR},
+ #{createdAt,jdbcType=BIGINT}
+ )
+ </insert>
+
+ <delete id="deleteBranch" parameterType="map">
+ delete from portfolio_proj_branches
+ where portfolio_project_uuid =
+ (select uuid from portfolio_projects
+ where portfolio_uuid = #{portfolioUuid,jdbcType=VARCHAR}
+ and project_uuid = #{projectUuid,jdbcType=VARCHAR})
+ and branch_key = #{branchKey,jdbcType=VARCHAR}
+ </delete>
+
<update id="update" parameterType="Portfolio">
update portfolios set
name = #{name,jdbcType=VARCHAR},
selection_mode = #{selectionMode,jdbcType=VARCHAR},
selection_expression = #{selectionExpression,jdbcType=VARCHAR},
parent_uuid = #{parentUuid,jdbcType=VARCHAR},
+ branch_name = #{branchName,jdbcType=VARCHAR},
root_uuid = #{rootUuid,jdbcType=VARCHAR},
updated_at = #{updatedAt,jdbcType=BIGINT}
where
ALTER TABLE "PLUGINS" ADD CONSTRAINT "PK_PLUGINS" PRIMARY KEY("UUID");
CREATE UNIQUE INDEX "PLUGINS_KEY" ON "PLUGINS"("KEE");
+CREATE TABLE "PORTFOLIO_PROJ_BRANCHES"(
+ "UUID" VARCHAR(40) NOT NULL,
+ "PORTFOLIO_PROJECT_UUID" VARCHAR(40) NOT NULL,
+ "BRANCH_KEY" VARCHAR(255) NOT NULL,
+ "CREATED_AT" BIGINT NOT NULL
+);
+ALTER TABLE "PORTFOLIO_PROJ_BRANCHES" ADD CONSTRAINT "PK_PORTFOLIO_PROJ_BRANCHES" PRIMARY KEY("UUID");
+
CREATE TABLE "PORTFOLIO_PROJECTS"(
"UUID" VARCHAR(40) NOT NULL,
"PORTFOLIO_UUID" VARCHAR(40) NOT NULL,
"SELECTION_MODE" VARCHAR(50) NOT NULL,
"SELECTION_EXPRESSION" VARCHAR(4000),
"CREATED_AT" BIGINT NOT NULL,
- "UPDATED_AT" BIGINT NOT NULL
+ "UPDATED_AT" BIGINT NOT NULL,
+ "BRANCH_NAME" VARCHAR(255)
);
ALTER TABLE "PORTFOLIOS" ADD CONSTRAINT "PK_PORTFOLIOS" PRIMARY KEY("UUID");
CREATE UNIQUE INDEX "UNIQ_PORTFOLIOS_KEE" ON "PORTFOLIOS"("KEE");
import org.sonar.db.project.ProjectDto;
import static java.util.Collections.emptySet;
-import static java.util.Map.entry;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.ArgumentMatchers.any;
@Test
public void delete() {
+ ProjectDto proj1 = db.components().insertPrivateProjectDto("proj1");
+ ProjectDto app1 = db.components().insertPrivateApplicationDto();
+
PortfolioDto p1 = db.components().insertPrivatePortfolioDto("p1");
PortfolioDto p2 = db.components().insertPrivatePortfolioDto("p2");
PortfolioDto p3 = db.components().insertPrivatePortfolioDto("p3");
PortfolioDto p4 = db.components().insertPrivatePortfolioDto("p4");
- portfolioDao.addProject(session, "p1", "proj1");
- portfolioDao.addProject(session, "p2", "proj1");
+ db.components().addPortfolioProject(p1, proj1);
+ db.components().addPortfolioProject(p2, proj1);
+ db.components().addPortfolioProjectBranch(p1, proj1, "branch1");
+ db.components().addPortfolioProjectBranch(p2, proj1, "branch2");
portfolioDao.addReference(session, "p1", "app1");
portfolioDao.addReference(session, "p2", "app1");
portfolioDao.delete(session, p1);
portfolioDao.delete(session, p3);
+ assertThat(db.select(session, "select branch_key from portfolio_proj_branches")).extracting(m -> m.values().iterator().next())
+ .containsOnly("branch2");
assertThat(db.select(session, "select uuid from portfolios")).extracting(m -> m.values().iterator().next())
.containsOnly("p2", "p4");
assertThat(db.select(session, "select portfolio_uuid from portfolio_references")).extracting(m -> m.values().iterator().next())
.extracting("name", "key", "uuid", "description", "private", "rootUuid", "parentUuid", "selectionMode", "selectionExpression")
.containsExactly("newName", "KEY_name", "name", "newDesc", true, "root", "parent", "newMode", "newExp");
verify(audit).updateComponent(any(), any());
-
- }
-
- @Test
- public void selectKeysByUuids() {
- PortfolioDto root = db.components().insertPrivatePortfolioDto();
- PortfolioDto child1 = addPortfolio(root);
-
- assertThat(portfolioDao.selectKeysByUuids(session, Set.of(root.getUuid(), child1.getUuid())))
- .containsOnly(entry(root.getUuid(), root.getKey()), entry(child1.getUuid(), child1.getKey()));
}
@Test
@Test
public void add_and_select_references() {
- assertThat(portfolioDao.selectProjects(session, "portfolio1")).isEmpty();
+ assertThat(portfolioDao.selectPortfolioProjects(session, "portfolio1")).isEmpty();
portfolioDao.addReference(session, "portfolio1", "app1");
portfolioDao.addReference(session, "portfolio1", "app2");
portfolioDao.addReference(session, "portfolio2", "app3");
@Test
public void insert_and_select_projects() {
- db.components().insertPrivateProject("project1");
- db.components().insertPrivateProject("project2");
+ PortfolioDto portfolio1 = db.components().insertPublicPortfolioDto();
+ PortfolioDto portfolio2 = db.components().insertPublicPortfolioDto();
+ PortfolioDto portfolio3 = db.components().insertPublicPortfolioDto();
- assertThat(portfolioDao.selectProjects(session, "portfolio1")).isEmpty();
- portfolioDao.addProject(session, "portfolio1", "project1");
- portfolioDao.addProject(session, "portfolio1", "project2");
- portfolioDao.addProject(session, "portfolio2", "project2");
+ ProjectDto project1 = db.components().insertPrivateProjectDto("project1");
+ ProjectDto project2 = db.components().insertPrivateProjectDto("project2");
+
+ assertThat(portfolioDao.selectPortfolioProjects(session, portfolio1.getUuid())).isEmpty();
+ db.components().addPortfolioProject(portfolio1, project1);
+ db.components().addPortfolioProject(portfolio1, project2);
+ db.components().addPortfolioProject(portfolio2, project2);
db.commit();
- assertThat(portfolioDao.selectProjects(session, "portfolio1")).extracting(ProjectDto::getUuid).containsOnly("project1", "project2");
- assertThat(portfolioDao.selectProjects(session, "portfolio2")).extracting(ProjectDto::getUuid).containsOnly("project2");
- assertThat(portfolioDao.selectProjects(session, "portfolio3")).isEmpty();
+ assertThat(portfolioDao.selectPortfolioProjects(session, portfolio1.getUuid())).extracting(PortfolioProjectDto::getProjectUuid).containsOnly("project1", "project2");
+ assertThat(portfolioDao.selectPortfolioProjects(session, portfolio2.getUuid())).extracting(PortfolioProjectDto::getProjectUuid).containsOnly("project2");
+ assertThat(portfolioDao.selectPortfolioProjects(session, portfolio3.getUuid())).isEmpty();
assertThat(db.countRowsOfTable("portfolio_projects")).isEqualTo(3);
assertThat(db.select(session, "select created_at from portfolio_projects"))
@Test
public void delete_projects() {
- db.components().insertPrivateProject("project1");
- db.components().insertPrivateProject("project2");
+ db.components().insertPrivatePortfolioDto("portfolio1");
+ db.components().insertPrivatePortfolioDto("portfolio2");
- assertThat(portfolioDao.selectProjects(session, "portfolio1")).isEmpty();
+ db.components().insertPrivateProjectDto("project1");
+ db.components().insertPrivateProjectDto("project2");
+
+ assertThat(portfolioDao.selectPortfolioProjects(session, "portfolio1")).isEmpty();
portfolioDao.addProject(session, "portfolio1", "project1");
portfolioDao.addProject(session, "portfolio1", "project2");
portfolioDao.addProject(session, "portfolio2", "project2");
- assertThat(portfolioDao.selectProjects(session, "portfolio1")).isNotEmpty();
+ assertThat(portfolioDao.selectPortfolioProjects(session, "portfolio1")).isNotEmpty();
portfolioDao.deleteProjects(session, "portfolio1");
- assertThat(portfolioDao.selectProjects(session, "portfolio1")).isEmpty();
- assertThat(portfolioDao.selectProjects(session, "portfolio2")).extracting(ProjectDto::getUuid).containsOnly("project2");
+ assertThat(portfolioDao.selectPortfolioProjects(session, "portfolio1")).isEmpty();
+ assertThat(portfolioDao.selectPortfolioProjects(session, "portfolio2")).extracting(PortfolioProjectDto::getProjectUuid).containsOnly("project2");
+ }
+
+ @Test
+ public void add_and_delete_selected_branches() {
+ PortfolioDto portfolio1 = db.components().insertPrivatePortfolioDto("portfolio1");
+ ProjectDto project1 = db.components().insertPrivateProjectDto("project1");
+ db.components().addPortfolioProject(portfolio1, project1);
+
+ assertThat(db.countRowsOfTable(db.getSession(), "portfolio_proj_branches")).isZero();
+ assertThat(portfolioDao.selectPortfolioProjectOrFail(db.getSession(), portfolio1.getUuid(), project1.getUuid()).getBranchKeys()).isEmpty();
+
+ db.components().addPortfolioProjectBranch(portfolio1, project1, "branch1");
+ assertThat(db.countRowsOfTable(db.getSession(), "portfolio_proj_branches")).isOne();
+ PortfolioProjectDto portfolioProject = portfolioDao.selectPortfolioProjectOrFail(db.getSession(), portfolio1.getUuid(), project1.getUuid());
+ assertThat(portfolioProject.getBranchKeys()).containsOnly("branch1");
+
+ portfolioDao.deleteBranch(db.getSession(), portfolio1.getUuid(), project1.getUuid(), "branch1");
+ assertThat(db.countRowsOfTable(db.getSession(), "portfolio_proj_branches")).isZero();
+ assertThat(portfolioDao.selectPortfolioProjectOrFail(db.getSession(), portfolio1.getUuid(), project1.getUuid()).getBranchKeys()).isEmpty();
+ }
+
+ @Test
+ public void delete_nonexisting_branch_doesnt_fail() {
+ DbSession session = db.getSession();
+ assertThatCode(() -> portfolioDao.deleteBranch(session, "nonexisting1", "nonexisting2", "branch1"))
+ .doesNotThrowAnyException();
}
@Test
public void delete_project() {
- db.components().insertPrivateProject("project1");
- db.components().insertPrivateProject("project2");
+ db.components().insertPrivatePortfolioDto("portfolio1");
+ db.components().insertPrivatePortfolioDto("portfolio2");
- assertThat(portfolioDao.selectProjects(session, "portfolio1")).isEmpty();
+ db.components().insertPrivateProjectDto("project1");
+ db.components().insertPrivateProjectDto("project2");
+
+ assertThat(portfolioDao.selectPortfolioProjects(session, "portfolio1")).isEmpty();
portfolioDao.addProject(session, "portfolio1", "project1");
portfolioDao.addProject(session, "portfolio1", "project2");
portfolioDao.addProject(session, "portfolio2", "project2");
- assertThat(portfolioDao.selectProjects(session, "portfolio1")).isNotEmpty();
+ assertThat(portfolioDao.selectPortfolioProjects(session, "portfolio1")).isNotEmpty();
portfolioDao.deleteProject(session, "portfolio1", "project2");
- assertThat(portfolioDao.selectProjects(session, "portfolio1")).extracting(ProjectDto::getUuid).containsOnly("project1");
- assertThat(portfolioDao.selectProjects(session, "portfolio2")).extracting(ProjectDto::getUuid).containsOnly("project2");
+ assertThat(portfolioDao.selectPortfolioProjects(session, "portfolio1")).extracting(PortfolioProjectDto::getProjectUuid).containsOnly("project1");
+ assertThat(portfolioDao.selectPortfolioProjects(session, "portfolio2")).extracting(PortfolioProjectDto::getProjectUuid).containsOnly("project2");
}
@Test
public void selectAllProjectsInHierarchy() {
- db.components().insertPrivateProject("p1");
- db.components().insertPrivateProject("p2");
- db.components().insertPrivateProject("p3");
- db.components().insertPrivateProject("p4");
+ ProjectDto p1 = db.components().insertPrivateProjectDto("p1");
+ ProjectDto p2 = db.components().insertPrivateProjectDto("p2");
+ ProjectDto p3 = db.components().insertPrivateProjectDto("p3");
+ ProjectDto p4 = db.components().insertPrivateProjectDto("p4");
PortfolioDto root = db.components().insertPrivatePortfolioDto("root");
PortfolioDto child1 = addPortfolio(root, "child1");
PortfolioDto child11 = addPortfolio(child1, "child11");
PortfolioDto root2 = db.components().insertPrivatePortfolioDto("root2");
- portfolioDao.addProject(session, root.getUuid(), "p1");
- portfolioDao.addProject(session, child1.getUuid(), "p2");
- portfolioDao.addProject(session, child11.getUuid(), "p3");
- portfolioDao.addProject(session, root2.getUuid(), "p4");
+ db.components().addPortfolioProject(root, p1);
+ db.components().addPortfolioProject(child1, p2);
+ db.components().addPortfolioProject(child11, p3);
+ db.components().addPortfolioProject(root2, p4);
+
+ db.components().addPortfolioProjectBranch(root, p1, "branch1");
session.commit();
assertThat(portfolioDao.selectAllProjectsInHierarchy(session, root.getUuid()))
- .extracting(PortfolioProjectDto::getProjectUuid).containsExactly("p1", "p2", "p3");
+ .extracting(PortfolioProjectDto::getProjectUuid, PortfolioProjectDto::getBranchKeys)
+ .containsExactlyInAnyOrder(tuple("p1", Set.of("branch1")), tuple("p2", emptySet()), tuple("p3", emptySet()));
assertThat(portfolioDao.selectAllProjectsInHierarchy(session, "nonexisting")).isEmpty();
}
PortfolioDto child11 = addPortfolio(child1);
PortfolioDto root2 = db.components().insertPrivatePortfolioDto();
- portfolioDao.addProject(session, root.getUuid(), "p1");
+ String portfolioProjectUuid = portfolioDao.addProject(session, root.getUuid(), "p1");
portfolioDao.addProject(session, child1.getUuid(), "p2");
portfolioDao.addProject(session, child11.getUuid(), "p3");
portfolioDao.addProject(session, root2.getUuid(), "p4");
+ portfolioDao.addBranch(session, portfolioProjectUuid, "branch1");
+
assertThat(db.countRowsOfTable(session, "portfolio_projects")).isEqualTo(4);
+ assertThat(db.countRowsOfTable(session, "portfolio_proj_branches")).isOne();
portfolioDao.deleteAllProjects(session);
assertThat(db.countRowsOfTable(session, "portfolio_projects")).isZero();
+ assertThat(db.countRowsOfTable(session, "portfolio_proj_branches")).isZero();
}
private PortfolioDto addPortfolio(PortfolioDto parent) {
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.portfolio.PortfolioDto;
+import org.sonar.db.portfolio.PortfolioProjectDto;
import org.sonar.db.project.ProjectDto;
import static com.google.common.base.Preconditions.checkArgument;
db.commit();
}
+ public void addPortfolioProjectBranch(PortfolioDto portfolio, ProjectDto project, String branchKey) {
+ PortfolioProjectDto portfolioProject = dbClient.portfolioDao().selectPortfolioProjectOrFail(dbSession, portfolio.getUuid(), project.getUuid());
+ dbClient.portfolioDao().addBranch(db.getSession(), portfolioProject.getUuid(), branchKey);
+ db.commit();
+ }
+
public final ComponentDto insertPublicApplication() {
return insertPublicApplication(defaults());
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.v92;
+
+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.VarcharColumnDef;
+import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class AddBranchToPortfolioProjects extends DdlChange {
+ private static final String TABLE_NAME = "portfolio_projects";
+ private static final String COLUMN_NAME = "branch_uuid";
+
+ public AddBranchToPortfolioProjects(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ try (Connection c = getDatabase().getDataSource().getConnection()) {
+ if (!DatabaseUtils.tableColumnExists(c, TABLE_NAME, COLUMN_NAME)) {
+ context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME)
+ .addColumn(VarcharColumnDef.newVarcharColumnDefBuilder().setColumnName(COLUMN_NAME).setIsNullable(true).setLimit(VarcharColumnDef.UUID_SIZE).build())
+ .build());
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.v92;
+
+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.VarcharColumnDef;
+import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class AddBranchToPortfolios extends DdlChange {
+ private static final String TABLE_NAME = "portfolios";
+ private static final String COLUMN_NAME = "branch_name";
+
+ public AddBranchToPortfolios(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ try (Connection c = getDatabase().getDataSource().getConnection()) {
+ if (!DatabaseUtils.tableColumnExists(c, TABLE_NAME, COLUMN_NAME)) {
+ context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME)
+ .addColumn(VarcharColumnDef.newVarcharColumnDefBuilder().setColumnName(COLUMN_NAME).setIsNullable(true).setLimit(255).build())
+ .build());
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.v92;
+
+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.sql.CreateIndexBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class AddIndexToPortfolioProjects extends DdlChange {
+ private static final String TABLE_NAME = "portfolio_projects";
+ private static final String INDEX_NAME = "uniq_portfolio_projects";
+
+ public AddIndexToPortfolioProjects(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ try (Connection c = getDatabase().getDataSource().getConnection()) {
+ if (!DatabaseUtils.indexExistsIgnoreCase(TABLE_NAME, INDEX_NAME, c)) {
+ context.execute(new CreateIndexBuilder()
+ .setName(INDEX_NAME)
+ .setTable(TABLE_NAME)
+ .addColumn("portfolio_uuid")
+ .addColumn("project_uuid")
+ .addColumn("branch_uuid")
+ .build());
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.v92;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.db.DatabaseUtils;
+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.UUID_SIZE;
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder;
+
+public class CreatePortfolioProjectBranchesTable extends DdlChange {
+ private final static String TABLE_NAME = "portfolio_proj_branches";
+
+ public CreatePortfolioProjectBranchesTable(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ if (!tableExists()) {
+ context.execute(new CreateTableBuilder(getDialect(), TABLE_NAME)
+ .addPkColumn(newVarcharColumnDefBuilder().setColumnName("uuid").setIsNullable(false).setLimit(UUID_SIZE).build())
+ .addColumn(newVarcharColumnDefBuilder().setColumnName("portfolio_project_uuid").setIsNullable(false).setLimit(UUID_SIZE).build())
+ .addColumn(newVarcharColumnDefBuilder().setColumnName("branch_key").setIsNullable(false).setLimit(255).build())
+ .addColumn(newBigIntegerColumnDefBuilder().setColumnName("created_at").setIsNullable(false).build())
+ .build());
+ }
+ }
+
+ private boolean tableExists() throws SQLException {
+ try (var connection = getDatabase().getDataSource().getConnection()) {
+ return DatabaseUtils.tableExists(TABLE_NAME, connection);
+ }
+ }
+}
.add(6104, "Create qgate_user_permissions Table", CreateQGateUserPermissionsTable.class)
.add(6105, "Create qgate_group_permissions Table", CreateQGateGroupPermissionsTable.class)
.add(6106, "Create column sonarlint_ad_seen in 'users'", AddSonarlintAdSeenColumnInUsersTable.class)
- .add(6107, "Upsert value of sonarlint_ad_seen in 'users'", UpsertSonarlintAdSeenValue.class);
+ .add(6107, "Upsert value of sonarlint_ad_seen in 'users'", UpsertSonarlintAdSeenValue.class)
+ .add(6108, "Create table 'portfolio_proj_branches'", CreatePortfolioProjectBranchesTable.class)
+ .add(6109, "Add column 'branch_name' to table 'portfolios'", AddBranchToPortfolios.class)
+ ;
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.v92;
+
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DropIndexChange;
+
+public class DropPortfolioProjectsIndex extends DropIndexChange {
+ private static final String TABLE_NAME = "portfolio_projects";
+
+ public DropPortfolioProjectsIndex(Database db) {
+ super(db, "uniq_portfolio_projects", TABLE_NAME);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.v92;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+public class AddBranchToPortfoliosTest {
+ private static final String TABLE_NAME = "portfolios";
+ private static final String COLUMN_NAME = "branch_name";
+
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createForSchema(AddBranchToPortfoliosTest.class, "schema.sql");
+
+ private final AddBranchToPortfolios underTest = new AddBranchToPortfolios(db.database());
+
+ @Test
+ public void migration_should_add_column() throws SQLException {
+ db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+ underTest.execute();
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, Types.VARCHAR, 255, true);
+ }
+
+ @Test
+ public void migration_should_be_reentrant() throws SQLException {
+ db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+ underTest.execute();
+ underTest.execute();
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, Types.VARCHAR, 255, true);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.v92;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+public class AddIndexToPortfolioProjectsTest {
+ private static final String TABLE_NAME = "portfolio_projects";
+ private static final String INDEX_NAME = "uniq_portfolio_projects";
+
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createForSchema(AddIndexToPortfolioProjectsTest.class, "schema.sql");
+
+ private final AddIndexToPortfolioProjects underTest = new AddIndexToPortfolioProjects(db.database());
+
+ @Test
+ public void migration_should_drop_PK_on_events() throws SQLException {
+ db.assertIndexDoesNotExist(TABLE_NAME, INDEX_NAME);
+ underTest.execute();
+ db.assertIndex(TABLE_NAME, INDEX_NAME, "portfolio_uuid", "project_uuid", "branch_uuid");
+ }
+
+ @Test
+ public void migration_should_be_reentant() throws SQLException {
+ db.assertIndexDoesNotExist(TABLE_NAME, INDEX_NAME);
+ underTest.execute();
+ underTest.execute();
+ db.assertIndex(TABLE_NAME, INDEX_NAME, "portfolio_uuid", "project_uuid", "branch_uuid");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.v92;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+public class CreatePortfolioProjectBranchesTableTest {
+ private static final String TABLE_NAME = "portfolio_proj_branches";
+
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createEmpty();
+
+ private final CreatePortfolioProjectBranchesTable underTest = new CreatePortfolioProjectBranchesTable(db.database());
+
+ @Test
+ public void migration_should_create_table() throws SQLException {
+ db.assertTableDoesNotExist(TABLE_NAME);
+
+ underTest.execute();
+
+ db.assertTableExists(TABLE_NAME);
+ }
+
+ @Test
+ public void migration_should_be_reentrant() throws SQLException {
+ db.assertTableDoesNotExist(TABLE_NAME);
+
+ underTest.execute();
+ //re-entrant
+ underTest.execute();
+
+ db.assertTableExists(TABLE_NAME);
+ }
+}
--- /dev/null
+CREATE TABLE "PORTFOLIO_PROJECTS"(
+ "UUID" VARCHAR(40) NOT NULL,
+ "PORTFOLIO_UUID" VARCHAR(40) NOT NULL,
+ "PROJECT_UUID" VARCHAR(40) NOT NULL,
+ "CREATED_AT" BIGINT NOT NULL
+);
+ALTER TABLE "PORTFOLIO_PROJECTS" ADD CONSTRAINT "PK_PORTFOLIO_PROJECTS" PRIMARY KEY("UUID");
--- /dev/null
+CREATE TABLE "PORTFOLIOS"(
+ "UUID" VARCHAR(40) NOT NULL,
+ "KEE" VARCHAR(400) NOT NULL,
+ "NAME" VARCHAR(2000) NOT NULL,
+ "DESCRIPTION" VARCHAR(2000),
+ "ROOT_UUID" VARCHAR(40) NOT NULL,
+ "PARENT_UUID" VARCHAR(40),
+ "PRIVATE" BOOLEAN NOT NULL,
+ "SELECTION_MODE" VARCHAR(50) NOT NULL,
+ "SELECTION_EXPRESSION" VARCHAR(4000),
+ "CREATED_AT" BIGINT NOT NULL,
+ "UPDATED_AT" BIGINT NOT NULL
+);
+ALTER TABLE "PORTFOLIOS" ADD CONSTRAINT "PK_PORTFOLIOS" PRIMARY KEY("UUID");
+CREATE UNIQUE INDEX "UNIQ_PORTFOLIOS_KEE" ON "PORTFOLIOS"("KEE");
--- /dev/null
+CREATE TABLE "PORTFOLIO_PROJECTS"(
+ "UUID" VARCHAR(40) NOT NULL,
+ "PORTFOLIO_UUID" VARCHAR(40) NOT NULL,
+ "PROJECT_UUID" VARCHAR(40) NOT NULL,
+ "BRANCH_UUID" VARCHAR(40),
+ "CREATED_AT" BIGINT NOT NULL
+);
+ALTER TABLE "PORTFOLIO_PROJECTS" ADD CONSTRAINT "PK_PORTFOLIO_PROJECTS" PRIMARY KEY("UUID");
--- /dev/null
+CREATE TABLE "PORTFOLIO_PROJECTS"(
+ "UUID" VARCHAR(40) NOT NULL,
+ "PORTFOLIO_UUID" VARCHAR(40) NOT NULL,
+ "PROJECT_UUID" VARCHAR(40) NOT NULL,
+ "CREATED_AT" BIGINT NOT NULL
+);
+ALTER TABLE "PORTFOLIO_PROJECTS" ADD CONSTRAINT "PK_PORTFOLIO_PROJECTS" PRIMARY KEY("UUID");
+CREATE UNIQUE INDEX "UNIQ_PORTFOLIO_PROJECTS" ON "PORTFOLIO_PROJECTS"("PORTFOLIO_UUID", "PROJECT_UUID");