import org.sonar.db.DbTester;
import org.sonar.db.component.BranchType;
import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ComponentTesting;
+import org.sonar.db.portfolio.PortfolioDto;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
// uuid is kept in memory for further calls with same key
assertThat(underTest.getOrCreateForKey("foo")).isEqualTo(generatedKey);
}
+
+ @Test
+ public void getOrCreateForKey_whenExistingComponentsInDbForPortfolioAndSubPortfolio_shouldLoadUuidsFromComponentTable() {
+ ComponentDto portfolioDto = db.components().insertPublicPortfolio("pft1", p -> p.setKey("root_portfolio"));
+ ComponentDto subView = db.components().insertSubView(portfolioDto, s -> s.setKey("sub_portfolio").setUuid("subPtf1"));
+ ComponentUuidFactory underTest = new ComponentUuidFactoryImpl(db.getDbClient(), db.getSession(), portfolioDto.getKey(), mockedBranch);
+
+ assertThat(underTest.getOrCreateForKey("root_portfolio")).isEqualTo(portfolioDto.uuid());
+ assertThat(underTest.getOrCreateForKey("sub_portfolio")).isEqualTo(subView.uuid());
+ }
+
+ @Test
+ public void getOrCreateForKey_whenNoExistingComponentsInDbForPortfolioAndSubPortfolio_shouldLoadUuidFromPortfolioTable() {
+ PortfolioDto portfolioDto = ComponentTesting.newPortfolioDto("uuid_ptf1", "ptf1", "Portfolio1", null);
+ db.getDbClient().portfolioDao().insert(db.getSession(), portfolioDto);
+ PortfolioDto subPortfolio = ComponentTesting.newPortfolioDto("subPtf1", "sub_ptf_1", "portfolio", portfolioDto);
+ db.getDbClient().portfolioDao().insert(db.getSession(), subPortfolio);
+
+ ComponentUuidFactory underTest = new ComponentUuidFactoryImpl(db.getDbClient(), db.getSession(), portfolioDto.getKey());
+
+ assertThat(underTest.getOrCreateForKey("ptf1")).isEqualTo(portfolioDto.getUuid());
+ assertThat(underTest.getOrCreateForKey("sub_ptf_1")).isEqualTo(subPortfolio.getUuid());
+ }
+
}
public class ComponentUuidFactoryImpl implements ComponentUuidFactory {
private final Map<String, String> uuidsByKey = new HashMap<>();
+ /** For the sake of consistency it is important that sub-portfolios have the same uuid as the associated component.
+ * As sub-portfolio have no component associated with their creation, it is necessary to look search for their uuid.
+ * see SONAR-19407 for more info
+ *
+ * @param dbClient
+ * @param dbSession
+ * @param rootKey
+ */
public ComponentUuidFactoryImpl(DbClient dbClient, DbSession dbSession, String rootKey) {
- List<KeyWithUuidDto> keys = dbClient.componentDao().selectUuidsByKeyFromProjectKey(dbSession, rootKey);
- keys.forEach(dto -> uuidsByKey.put(dto.key(), dto.uuid()));
+ List<KeyWithUuidDto> projectKeys = dbClient.componentDao().selectUuidsByKeyFromProjectKey(dbSession, rootKey);
+ List<KeyWithUuidDto> portFolioKeys = dbClient.portfolioDao().selectUuidsByKey(dbSession, rootKey);
+ projectKeys.forEach(dto -> uuidsByKey.put(dto.key(), dto.uuid()));
+ portFolioKeys.forEach(dto -> uuidsByKey.putIfAbsent(dto.key(), dto.uuid()));
}
public ComponentUuidFactoryImpl(DbClient dbClient, DbSession dbSession, String rootKey, Branch branch) {
*/
package org.sonar.db.portfolio;
+import java.util.Arrays;
+import java.util.List;
import java.util.Set;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.db.DbTester;
import org.sonar.db.audit.AuditPersister;
import org.sonar.db.component.BranchDto;
+import org.sonar.db.component.ComponentTesting;
+import org.sonar.db.component.KeyWithUuidDto;
import org.sonar.db.component.ProjectData;
import org.sonar.db.project.ApplicationProjectDto;
import org.sonar.db.project.ProjectDto;
tuple("NAME_name2", "KEY_name2", "name2", "DESCRIPTION_name2", "name2", null, "NONE", null));
}
+ @Test
+ public void selectUuidsByKeyFromPortfolioKey_returns_all_uuidByKeyForPortfoliosLinkedToRootKey() {
+ PortfolioDto portfolio1 = ComponentTesting.newPortfolioDto("uuid1", "ptf1", "Portfolio 1", null);
+ PortfolioDto subPortfolio1 = ComponentTesting.newPortfolioDto("sub_uuid11", "sub_ptf1", "SubPortfolio 1", portfolio1);
+ PortfolioDto subSubPortfolio1 = ComponentTesting.newPortfolioDto("sub_uuid12", "sub_sub_ptf1", "SubSubPortfolio 1", portfolio1);
+ PortfolioDto portfolio2 = ComponentTesting.newPortfolioDto("uuid2", "ptf2", "Portfolio 2", null);
+ PortfolioDto subPortfolio2 = ComponentTesting.newPortfolioDto("sub_uuid21", "sub_ptd2", "SubPortfolio 2", portfolio2);
+ Arrays.asList(portfolio1, subPortfolio1, subSubPortfolio1, portfolio2, subPortfolio2)
+ .forEach(portfolio -> portfolioDao.insert(db.getSession(), portfolio));
+
+ List<KeyWithUuidDto> keyWithUuidDtos = portfolioDao.selectUuidsByKey(db.getSession(), portfolio1.getKey());
+
+ KeyWithUuidDto[] expectedKey = {
+ new KeyWithUuidDto(portfolio1.getKee(), portfolio1.getUuid()),
+ new KeyWithUuidDto(subPortfolio1.getKee(), subPortfolio1.getUuid()),
+ new KeyWithUuidDto(subSubPortfolio1.getKee(), subSubPortfolio1.getUuid())
+ };
+
+ assertThat(keyWithUuidDtos).containsExactlyInAnyOrder(expectedKey);
+ }
+
@Test
public void insert_fails_if_root_is_inconsistent_with_parent() {
PortfolioDto portfolio = new PortfolioDto()
import javax.annotation.concurrent.Immutable;
@Immutable
-public class KeyWithUuidDto {
-
- private final String kee;
- private final String uuid;
-
- public KeyWithUuidDto(String kee, String uuid) {
- this.kee = kee;
- this.uuid = uuid;
- }
+public record KeyWithUuidDto(String kee, String uuid) {
public String key() {
return kee;
}
-
- public String uuid() {
- return uuid;
- }
}
import org.sonar.db.DbSession;
import org.sonar.db.audit.AuditPersister;
import org.sonar.db.audit.model.ComponentNewValue;
+import org.sonar.db.component.KeyWithUuidDto;
import org.sonar.db.project.ApplicationProjectDto;
import static com.google.common.base.Preconditions.checkArgument;
return mapper(dbSession).selectByUuids(uuids);
}
+ public List<KeyWithUuidDto> selectUuidsByKey(DbSession dbSession, String rootKey) {
+ return mapper(dbSession).selectUuidsByKey(rootKey);
+ }
+
/*
* Modify portfolios
*/
}
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)));
+ 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) {
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.ibatis.annotations.Param;
+import org.sonar.db.component.KeyWithUuidDto;
import org.sonar.db.project.ApplicationProjectDto;
public interface PortfolioMapper {
List<ReferenceDto> selectAllReferencesToApplicationsInHierarchy(String rootUuid);
List<PortfolioDto> selectRootOfReferencersToAppBranch(@Param("appUuid") String appUuid, @Param("appBranchKey") String appBranchKey);
+
+ List<KeyWithUuidDto> selectUuidsByKey(@Param("rootKey") String rootKey);
}
when b_qualifier = 'DIR' THEN 'DIR'
when b_qualifier = 'FIL' THEN 'FIL'
when b_qualifier = 'UTS' THEN 'FIL'
- <!-- For the few cases where qualifier is not enough to guess the scope (like TRK), just assume the scope remains unchanged -->
- else scope
+ <!-- For the few cases where qualifier is not enough to guess the scope (like TRK), just assume the scope remains unchanged -->
+ else scope
end
),
b_changed = ${_false},
AND target.kee=#{referenceKey,jdbcType=VARCHAR}
</select>
+ <select id="selectUuidsByKey" parameterType="string" resultType="KeyWithUuid">
+ SELECT ptf.kee, ptf.uuid
+ FROM portfolios ptf
+ INNER JOIN
+ portfolios root ON root.uuid = ptf.root_uuid
+ WHERE root.kee = #{rootKey,jdbcType=VARCHAR}
+ </select>
+
<insert id="insert" parameterType="Portfolio">
INSERT INTO portfolios (
kee,
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.core.util.Uuids;
+import org.sonar.db.portfolio.PortfolioDto;
import org.sonar.db.project.ProjectDto;
import static com.google.common.base.Preconditions.checkArgument;
import static org.sonar.db.component.ComponentDto.UUID_PATH_OF_ROOT;
import static org.sonar.db.component.ComponentDto.formatUuidPathFromParent;
import static org.sonar.db.component.ComponentDto.generateBranchKey;
+import static org.sonar.db.portfolio.PortfolioDto.SelectionMode.NONE;
public class ComponentTesting {
.setPrivate(false);
}
+ public static PortfolioDto newPortfolioDto(String uuid, String key, String name, @Nullable PortfolioDto parent) {
+ return new PortfolioDto()
+ .setUuid(uuid)
+ .setKey(key)
+ .setParentUuid(parent == null ? null : parent.getUuid())
+ .setRootUuid(parent == null ? uuid : parent.getRootUuid())
+ .setSelectionMode(NONE.name())
+ .setCreatedAt(1L)
+ .setUpdatedAt(1L)
+ .setPrivate(false)
+ .setName(name);
+ }
+
public static ComponentDto newApplication() {
return newPortfolio(Uuids.createFast()).setQualifier(Qualifiers.APP);
}