From 7515f738fb15473d144dd376fac2a1562486c049 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Thu, 27 Jul 2017 09:12:49 +0200 Subject: [PATCH] SONAR-9616 compute engine backend to support branches --- .../ComputeEngineContainerImplTest.java | 2 +- .../java/org/sonar/db/version/SqTables.java | 2 +- .../org/sonar/db/version/schema-h2.ddl | 3 +- .../src/main/java/org/sonar/db/DbClient.java | 8 + .../org/sonar/db/component/BranchDao.java | 24 + .../org/sonar/db/component/BranchDto.java | 54 +- .../org/sonar/db/component/BranchMapper.java | 7 + .../org/sonar/db/component/ComponentDto.java | 33 +- .../org/sonar/db/property/PropertiesDao.java | 10 +- .../sonar/db/property/PropertiesMapper.java | 2 +- .../org/sonar/db/component/BranchMapper.xml | 29 +- .../sonar/db/property/PropertiesMapper.xml | 7 +- .../org/sonar/db/component/BranchDaoTest.java | 175 +++++ .../org/sonar/db/component/BranchDtoTest.java | 45 ++ .../sonar/db/component/ComponentDaoTest.java | 26 +- .../sonar/db/property/PropertiesDaoTest.java | 21 - .../v66/AddBranchColumnToProjectsTable.java | 1 - .../v66/CreateTableProjectBranches.java | 4 + .../v66/CreateTableProjectBranchesTest.java | 1 + .../computation/queue/ReportSubmitter.java | 9 +- .../analysis/AnalysisMetadataHolder.java | 23 +- .../analysis/AnalysisMetadataHolderImpl.java | 23 +- .../task/projectanalysis/analysis/Branch.java | 45 ++ .../MutableAnalysisMetadataHolder.java | 7 +- .../projectanalysis/analysis/Project.java | 91 +++ .../MeasureComputerContextImpl.java | 9 +- .../component/BranchLoader.java | 57 ++ .../component/BranchLoaderDelegate.java | 30 + .../component/BranchPersisterDelegate.java | 30 + .../projectanalysis/component/Component.java | 4 +- .../component/ComponentKeyGenerator.java | 30 + .../component/ComponentTreeBuilder.java | 204 +++++ ...Factory.java => ComponentUuidFactory.java} | 18 +- .../component/ConfigurationRepository.java | 10 +- .../ConfigurationRepositoryImpl.java | 32 +- .../component/MainBranchImpl.java | 82 ++ .../component/TreeRootHolder.java | 2 +- ...ProjectAnalysisTaskContainerPopulator.java | 5 +- ...ossProjectDuplicationStatusHolderImpl.java | 11 +- .../issue/DefaultAssignee.java | 7 +- .../issue/filter/IssueFilter.java | 5 +- .../qualitygate/QualityGateServiceImpl.java | 2 +- .../step/BuildComponentTreeStep.java | 113 +-- .../projectanalysis/step/LoadPeriodsStep.java | 2 +- .../step/LoadQualityGateStep.java | 29 +- .../LoadReportAnalysisMetadataHolderStep.java | 100 ++- .../step/PersistComponentsStep.java | 253 +++--- .../step/PurgeDatastoresStep.java | 2 +- .../step/QualityGateEventsStep.java | 2 +- .../step/ReportComputationSteps.java | 1 + .../step/ValidateProjectStep.java | 13 +- .../step/VerifyBillingStep.java | 57 ++ .../webhook/WebhookPostTask.java | 9 +- .../BillingValidationsProxyImpl.java | 7 +- .../permission/PermissionTemplateService.java | 7 +- .../server/project/ws/BranchesAction.java | 85 ++ .../server/project/ws/ProjectsWsModule.java | 1 + .../queue/ReportSubmitterTest.java | 21 +- .../analysis/AnalysisImplTest.java | 6 +- .../AnalysisMetadataHolderImplTest.java | 44 +- .../analysis/AnalysisMetadataHolderRule.java | 23 +- .../MutableAnalysisMetadataHolderRule.java | 21 +- .../projectanalysis/analysis/ProjectTest.java | 65 ++ .../MeasureComputerContextImplTest.java | 4 +- .../component/BranchLoaderTest.java | 107 +++ .../component/ComponentFunctionsTest.java | 7 +- .../component/ComponentRootBuilderTest.java | 545 ------------- .../component/ComponentTreeBuilderTest.java | 735 ++++++++++++++++++ .../component/ComponentUuidFactoryTest.java | 57 ++ .../ConfigurationRepositoryTest.java | 79 +- .../component/MainBranchImplTest.java | 92 +++ .../component/TestSettingsRepository.java | 2 +- ...rojectDuplicationStatusHolderImplTest.java | 21 +- .../issue/DefaultAssigneeTest.java | 7 +- .../issue/filter/IssueFilterTest.java | 20 +- .../step/BuildComponentTreeStepTest.java | 48 +- .../step/LoadPeriodsStepTest.java | 2 +- ...Test.java => LoadQualityGateStepTest.java} | 39 +- ...dReportAnalysisMetadataHolderStepTest.java | 133 +--- .../step/PersistComponentsStepTest.java | 4 +- .../step/PurgeDatastoresStepTest.java | 2 +- .../step/ReportPersistComponentsStepTest.java | 401 ++++++---- .../step/ValidateProjectStepTest.java | 34 +- .../step/VerifyBillingStepTest.java | 80 ++ .../step/ViewsPersistComponentsStepTest.java | 6 +- .../webhook/WebhookPostTaskTest.java | 7 +- .../PermissionTemplateServiceTest.java | 4 +- .../project/ws/ProjectsWsModuleTest.java | 2 +- .../core/config/CorePropertyDefinitions.java | 32 +- .../sonar/core/config/PurgeProperties.java | 5 +- .../sonar/core/config/ScannerProperties.java | 76 ++ .../sonar/core/config/WebhookProperties.java | 5 +- .../org/sonar/core/platform/PluginLoader.java | 2 +- .../config/CorePropertyDefinitionsTest.java | 10 +- .../java/org/sonar/api/CoreProperties.java | 5 - .../sonar/scanner/mediumtest/TaskResult.java | 20 +- .../scanner/report/MetadataPublisher.java | 13 +- .../sonar/scanner/report/ReportPublisher.java | 6 +- .../DefaultQualityProfileLoader.java | 4 +- .../mediumtest/branch/BranchMediumTest.java | 4 +- .../scanner/report/MetadataPublisherTest.java | 5 +- .../scanner/report/ReportPublisherTest.java | 8 +- .../viewer/ScannerReportViewerApp.java | 2 +- .../src/main/protobuf/scanner_report.proto | 4 +- sonar-ws/src/main/protobuf/ws-projects.proto | 21 + .../.scannerwork/.sonar_lock | 0 .../.scannerwork/report-task.txt | 6 + 107 files changed, 3292 insertions(+), 1425 deletions(-) create mode 100644 server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java create mode 100644 server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDtoTest.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/Branch.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/Project.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/BranchLoader.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/BranchLoaderDelegate.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/BranchPersisterDelegate.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentKeyGenerator.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilder.java rename server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/{UuidFactory.java => ComponentUuidFactory.java} (69%) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/MainBranchImpl.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/VerifyBillingStep.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/project/ws/BranchesAction.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/ProjectTest.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/BranchLoaderTest.java delete mode 100644 server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentRootBuilderTest.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilderTest.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentUuidFactoryTest.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/MainBranchImplTest.java rename server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/{QualityGateLoadingStepTest.java => LoadQualityGateStepTest.java} (60%) create mode 100644 server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/VerifyBillingStepTest.java create mode 100644 sonar-core/src/main/java/org/sonar/core/config/ScannerProperties.java create mode 100644 tests/projects/shared/xoo-multi-module-sample-without-project-name-version/.scannerwork/.sonar_lock create mode 100644 tests/projects/shared/xoo-multi-module-sample-without-project-name-version/.scannerwork/report-task.txt diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java index a562760d4bb..405fbe25e34 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java @@ -148,7 +148,7 @@ public class ComputeEngineContainerImplTest { + 25 // level 1 + 49 // content of DaoModule + 3 // content of EsSearchModule - + 61 // content of CorePropertyDefinitions + + 63 // content of CorePropertyDefinitions + 1 // StopFlagContainer ); assertThat( diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java b/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java index c92eb1734e0..35c2a91d202 100644 --- a/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java +++ b/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java @@ -80,10 +80,10 @@ public final class SqTables { "perm_tpl_characteristics", "plugins", "projects", + "project_branches", "project_links", "project_measures", "project_qprofiles", - "project_branches", "properties", "qprofile_changes", "quality_gates", diff --git a/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl b/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl index 7f5d6724427..ec2b6a3ac79 100644 --- a/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl +++ b/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl @@ -701,7 +701,8 @@ CREATE TABLE "PROJECT_BRANCHES" ( "BRANCH_TYPE" VARCHAR(5), "MERGE_BRANCH_UUID" VARCHAR(50), "PULL_REQUEST_TITLE" VARCHAR(4000), - "CREATED_AT" BIGINT NOT NULL + "CREATED_AT" BIGINT NOT NULL, + "UPDATED_AT" BIGINT NOT NULL ); CREATE UNIQUE INDEX "PK_PROJECT_BRANCHES" ON "PROJECT_BRANCHES" ("UUID"); CREATE UNIQUE INDEX "PROJECT_BRANCHES_KEE" ON "PROJECT_BRANCHES" ("PROJECT_UUID", "KEE_TYPE", "KEE"); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java index 246bb15f559..f694b925d14 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java @@ -26,6 +26,7 @@ import org.sonar.db.ce.CeQueueDao; import org.sonar.db.ce.CeScannerContextDao; import org.sonar.db.ce.CeTaskCharacteristicDao; import org.sonar.db.ce.CeTaskInputDao; +import org.sonar.db.component.BranchDao; import org.sonar.db.component.ComponentDao; import org.sonar.db.component.ComponentKeyUpdaterDao; import org.sonar.db.component.ComponentLinkDao; @@ -75,6 +76,7 @@ public class DbClient { private final Database database; private final MyBatis myBatis; private final DBSessions dbSessions; + private final SchemaMigrationDao schemaMigrationDao; private final AuthorizationDao authorizationDao; private final OrganizationDao organizationDao; @@ -123,6 +125,7 @@ public class DbClient { private final DefaultQProfileDao defaultQProfileDao; private final EsQueueDao esQueueDao; private final PluginDao pluginDao; + private final BranchDao branchDao; public DbClient(Database database, MyBatis myBatis, DBSessions dbSessions, Dao... daos) { this.database = database; @@ -181,6 +184,7 @@ public class DbClient { defaultQProfileDao = getDao(map, DefaultQProfileDao.class); esQueueDao = getDao(map, EsQueueDao.class); pluginDao = getDao(map, PluginDao.class); + branchDao = getDao(map, BranchDao.class); } public DbSession openSession(boolean batch) { @@ -383,6 +387,10 @@ public class DbClient { return pluginDao; } + public BranchDao branchDao() { + return branchDao; + } + protected K getDao(Map map, Class clazz) { return (K) map.get(clazz); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java index 126dda1ada3..6519c318411 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java @@ -19,6 +19,9 @@ */ package org.sonar.db.component; +import java.util.Collection; +import java.util.Optional; +import javax.annotation.Nullable; import org.sonar.api.utils.System2; import org.sonar.db.Dao; import org.sonar.db.DbSession; @@ -35,6 +38,27 @@ public class BranchDao implements Dao { mapper(dbSession).insert(dto, system2.now()); } + public void upsert(DbSession dbSession, BranchDto dto) { + BranchMapper mapper = mapper(dbSession); + long now = system2.now(); + if (mapper.update(dto, now) == 0) { + mapper.insert(dto, now); + } + } + + public Optional selectByKey(DbSession dbSession, String projectUuid, BranchKeyType keyType, @Nullable String key) { + String keyInDb = BranchDto.convertKeyToDb(key); + return Optional.ofNullable(mapper(dbSession).selectByKey(projectUuid, keyType, keyInDb)); + } + + public Collection selectByComponent(DbSession dbSession, ComponentDto component) { + String projectUuid = component.getMainBranchProjectUuid(); + if (projectUuid == null) { + projectUuid = component.projectUuid(); + } + return mapper(dbSession).selectByProjectUuid(projectUuid); + } + private static BranchMapper mapper(DbSession dbSession) { return dbSession.getMapper(BranchMapper.class); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDto.java index 7192a6d4683..f3a71679f55 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDto.java @@ -19,19 +19,26 @@ */ package org.sonar.db.component; +import javax.annotation.CheckForNull; import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkArgument; +import static org.apache.commons.lang.StringUtils.repeat; public class BranchDto { + /** + * Maximum length of column "kee" + */ + public static final int KEE_MAX_LENGTH = 255; + /** * Value of {@link #kee} when the name of main branch is not known. * Used only if {@link #keeType} is {@link BranchKeyType#BRANCH}. - * It does not conflict with names of real branches because the character ':' + * It does not conflict with names of real branches because the term ':BRANCH:' * is not accepted. */ - public static final String DEFAULT_KEY_OF_MAIN_BRANCH = ":main:"; + public static final String NULL_KEY = repeat("_", KEE_MAX_LENGTH); /** * Branch UUID is the projects.uuid that reference projects, branches or pull requests @@ -56,7 +63,7 @@ public class BranchDto { /** * If {@link #keeType} is {@link BranchKeyType#BRANCH}, then name of branch, for example - * "feature/foo". Can be {@link #DEFAULT_KEY_OF_MAIN_BRANCH} is the name is not known. + * "feature/foo". Can be {@link #NULL_KEY} is the name is not known. * * If {@link #keeType} is {@link BranchKeyType#PR}, then id of the pull request, for * example "1204". @@ -102,6 +109,10 @@ public class BranchDto { this.projectUuid = s; } + public boolean isMain() { + return projectUuid.equals(uuid); + } + public BranchKeyType getKeeType() { return keeType; } @@ -110,15 +121,33 @@ public class BranchDto { this.keeType = t; } - public String getKee() { + /** + * This is the getter used by MyBatis mapper. It does + * not handle the special value used to map null field. + */ + private String getKee() { return kee; } - public void setKee(String s) { - checkArgument(s.length() <= 255, "Maximum length of branch name or pull request id is 255: %s", s); + @CheckForNull + public String getKey() { + return convertKeyFromDb(getKee()); + } + + /** + * This is the setter used by MyBatis mapper. It does + * not handle the special value used to map null field. + */ + private void setKee(String s) { this.kee = s; } + public void setKey(@Nullable String s) { + checkArgument(s == null || s.length() <= KEE_MAX_LENGTH, "Maximum length of branch name or pull request id is %s: %s", KEE_MAX_LENGTH, s); + checkArgument(!NULL_KEY.equals(s), "Branch name is not allowed: %s", s); + setKee(convertKeyToDb(s)); + } + @Nullable public BranchType getBranchType() { return branchType; @@ -151,9 +180,22 @@ public class BranchDto { public String toString() { StringBuilder sb = new StringBuilder("BranchDto{"); sb.append("uuid='").append(uuid).append('\''); + sb.append(", projectUuid='").append(projectUuid).append('\''); + sb.append(", keeType=").append(keeType); + sb.append(", kee='").append(kee).append('\''); + sb.append(", branchType=").append(branchType); sb.append(", mergeBranchUuid='").append(mergeBranchUuid).append('\''); sb.append(", pullRequestTitle='").append(pullRequestTitle).append('\''); sb.append('}'); return sb.toString(); } + + static String convertKeyToDb(@Nullable String s) { + return s == null ? NULL_KEY : s; + } + + @CheckForNull + static String convertKeyFromDb(String s) { + return NULL_KEY.equals(s) ? null : s; + } } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java index 505381a632f..41cf1360f3d 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java @@ -19,10 +19,17 @@ */ package org.sonar.db.component; +import java.util.Collection; import org.apache.ibatis.annotations.Param; public interface BranchMapper { void insert(@Param("dto") BranchDto dto, @Param("now") long now); + int update(@Param("dto") BranchDto dto, @Param("now") long now); + + BranchDto selectByKey(@Param("projectUuid") String projectUuid, + @Param("keyType") BranchKeyType keyType, @Param("key") String key); + + Collection selectByProjectUuid(@Param("projectUuid") String projectUuid); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDto.java index 58a6fe02ed7..9e3b55062fa 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDto.java @@ -216,9 +216,6 @@ public class ComponentDto { return this; } - public String getKey() { - return getDbKey(); - } public String scope() { return scope; @@ -476,4 +473,34 @@ public class ComponentDto { .append("private", isPrivate) .toString(); } + + public ComponentDto copy() { + ComponentDto copy = new ComponentDto(); + copy.projectUuid = projectUuid; + copy.id = id; + copy.organizationUuid = organizationUuid; + copy.kee = kee; + copy.uuid = uuid; + copy.uuidPath = uuidPath; + copy.projectUuid = projectUuid; + copy.rootUuid = rootUuid; + copy.mainBranchProjectUuid = mainBranchProjectUuid; + copy.moduleUuid = moduleUuid; + copy.moduleUuidPath = moduleUuidPath; + copy.copyComponentUuid = copyComponentUuid; + copy.developerUuid = developerUuid; + copy.scope = scope; + copy.qualifier = qualifier; + copy.path = path; + copy.deprecatedKey = deprecatedKey; + copy.name = name; + copy.longName = longName; + copy.language = language; + copy.description = description; + copy.tags = tags; + copy.enabled = enabled; + copy.isPrivate = isPrivate; + copy.createdAt = createdAt; + return copy; + } } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesDao.java index 966b5a564b0..f12f1027cfb 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesDao.java @@ -153,11 +153,7 @@ public class PropertiesDao implements Dao { } public List selectGlobalPropertiesByKeys(DbSession session, Set keys) { - return selectByKeys(session, keys, null); - } - - public List selectPropertiesByKeysAndComponentId(DbSession session, Set keys, long componentId) { - return selectByKeys(session, keys, componentId); + return executeLargeInputs(keys, partitionKeys -> getMapper(session).selectByKeys(partitionKeys)); } public List selectPropertiesByKeysAndComponentIds(DbSession session, Set keys, Set componentIds) { @@ -169,10 +165,6 @@ public class PropertiesDao implements Dao { return executeLargeInputs(componentIds, getMapper(session)::selectByComponentIds); } - private List selectByKeys(DbSession session, Set keys, @Nullable Long componentId) { - return executeLargeInputs(keys, partitionKeys -> getMapper(session).selectByKeys(partitionKeys, componentId)); - } - public List selectGlobalPropertiesByKeyQuery(DbSession session, String keyQuery) { return getMapper(session).selectGlobalPropertiesByKeyQuery(buildLikeValue(keyQuery, WildcardPosition.BEFORE_AND_AFTER)); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesMapper.java index b687a121834..ac422e3cd1d 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesMapper.java @@ -35,7 +35,7 @@ public interface PropertiesMapper { PropertyDto selectByKey(PropertyDto key); - List selectByKeys(@Param("keys") List keys, @Nullable @Param("componentId") Long componentId); + List selectByKeys(@Param("keys") List keys); List selectByKeysAndComponentIds(@Param("keys") List keys, @Param("componentIds") List componentIds); diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml index e05ac532f73..c5a6de69a93 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml @@ -21,7 +21,8 @@ branch_type, merge_branch_uuid, pull_request_title, - created_at + created_at, + updated_at ) values ( #{dto.uuid, jdbcType=VARCHAR}, #{dto.projectUuid, jdbcType=VARCHAR}, @@ -30,8 +31,34 @@ #{dto.branchType, jdbcType=VARCHAR}, #{dto.mergeBranchUuid, jdbcType=VARCHAR}, #{dto.pullRequestTitle, jdbcType=VARCHAR}, + #{now, jdbcType=BIGINT}, #{now, jdbcType=BIGINT} ) + + update project_branches + set + merge_branch_uuid = #{dto.mergeBranchUuid, jdbcType=VARCHAR}, + pull_request_title = #{dto.pullRequestTitle, jdbcType=VARCHAR}, + updated_at = #{now, jdbcType=BIGINT} + where + uuid = #{dto.uuid, jdbcType=VARCHAR} + + + + + diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/property/PropertiesMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/property/PropertiesMapper.xml index 26dca324c56..a9a520eb1ee 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/property/PropertiesMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/property/PropertiesMapper.xml @@ -123,12 +123,7 @@ #{key} - - and p.resource_id is null - - - and p.resource_id=#{componentId} - + and p.resource_id is null and p.user_id is null order by p.id diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java new file mode 100644 index 00000000000..5133effde68 --- /dev/null +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java @@ -0,0 +1,175 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.component; + +import java.util.Map; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.utils.System2; +import org.sonar.api.utils.internal.TestSystem2; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; + +import static org.apache.commons.lang.StringUtils.repeat; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +public class BranchDaoTest { + + private static final long NOW = 1_000L; + private static final String SELECT_FROM = "select project_uuid as \"projectUuid\", uuid as \"uuid\", branch_type as \"branchType\", kee_type as \"keeType\", " + + "kee as \"kee\", merge_branch_uuid as \"mergeBranchUuid\", pull_request_title as \"pullRequestTitle\", created_at as \"createdAt\", updated_at as \"updatedAt\" " + + "from project_branches "; + private System2 system2 = new TestSystem2().setNow(NOW); + + @Rule + public DbTester db = DbTester.create(system2); + + private DbSession dbSession = db.getSession(); + private BranchDao underTest = new BranchDao(system2); + + @Test + public void insert_branch_with_only_nonnull_fields() { + BranchDto dto = new BranchDto(); + dto.setProjectUuid("U1"); + dto.setUuid("U2"); + dto.setBranchType(BranchType.SHORT); + dto.setKeeType(BranchKeyType.BRANCH); + dto.setKey("feature/foo"); + + underTest.insert(dbSession, dto); + + Map map = db.selectFirst(dbSession, SELECT_FROM + " where uuid='" + dto.getUuid() + "'"); + assertThat(map).contains( + entry("projectUuid", "U1"), + entry("uuid", "U2"), + entry("branchType", "SHORT"), + entry("keeType", "BRANCH"), + entry("kee", "feature/foo"), + entry("mergeBranchUuid", null), + entry("pullRequestTitle", null), + entry("createdAt", 1_000L), + entry("updatedAt", 1_000L) + ); + } + + @Test + public void insert_branch_with_all_fields_and_max_length_values() { + BranchDto dto = new BranchDto(); + dto.setProjectUuid(repeat("a", 50)); + dto.setUuid(repeat("b", 50)); + dto.setBranchType(BranchType.SHORT); + dto.setKeeType(BranchKeyType.BRANCH); + dto.setKey(repeat("c", 255)); + dto.setMergeBranchUuid(repeat("d", 50)); + dto.setPullRequestTitle(repeat("e", 4_000)); + + underTest.insert(dbSession, dto); + + Map map = db.selectFirst(dbSession, SELECT_FROM + " where uuid='" + dto.getUuid() + "'"); + assertThat((String)map.get("projectUuid")).contains("a").isEqualTo(dto.getProjectUuid()); + assertThat((String)map.get("uuid")).contains("b").isEqualTo(dto.getUuid()); + assertThat((String)map.get("kee")).contains("c").isEqualTo(dto.getKey()); + assertThat((String)map.get("mergeBranchUuid")).contains("d").isEqualTo(dto.getMergeBranchUuid()); + assertThat((String)map.get("pullRequestTitle")).contains("e").isEqualTo(dto.getPullRequestTitle()); + } + + @Test + public void null_value_of_kee_column_is_converted_in_db() { + BranchDto dto = new BranchDto(); + dto.setProjectUuid("u1"); + dto.setUuid("u2"); + dto.setKeeType(BranchKeyType.BRANCH); + dto.setKey(null); + + underTest.insert(dbSession, dto); + + Map map = db.selectFirst(dbSession, SELECT_FROM + " where uuid='" + dto.getUuid() + "'"); + assertThat(map).contains(entry("kee", BranchDto.NULL_KEY)); + BranchDto loaded = underTest.selectByKey(dbSession, dto.getProjectUuid(), dto.getKeeType(), null).get(); + assertThat(loaded.getKey()).isNull(); + } + + @Test + public void upsert() { + BranchDto dto = new BranchDto(); + dto.setProjectUuid("U1"); + dto.setUuid("U2"); + dto.setBranchType(BranchType.LONG); + dto.setKeeType(BranchKeyType.BRANCH); + dto.setKey("foo"); + underTest.insert(dbSession, dto); + + // the fields that can be updated + dto.setMergeBranchUuid("U3"); + dto.setPullRequestTitle("theTitle"); + + // the fields that can't be updated. New values are ignored. + dto.setProjectUuid("ignored"); + dto.setBranchType(BranchType.SHORT); + dto.setKeeType(BranchKeyType.PR); + underTest.upsert(dbSession, dto); + + BranchDto loaded = underTest.selectByKey(dbSession, "U1", BranchKeyType.BRANCH, "foo").get(); + assertThat(loaded.getMergeBranchUuid()).isEqualTo("U3"); + assertThat(loaded.getPullRequestTitle()).isEqualTo("theTitle"); + assertThat(loaded.getProjectUuid()).isEqualTo("U1"); + assertThat(loaded.getBranchType()).isEqualTo(BranchType.LONG); + assertThat(loaded.getKeeType()).isEqualTo(BranchKeyType.BRANCH); + } + + @Test + public void selectByKey() { + BranchDto mainBranch = new BranchDto(); + mainBranch.setProjectUuid("U1"); + mainBranch.setUuid("U1"); + mainBranch.setBranchType(BranchType.LONG); + mainBranch.setKeeType(BranchKeyType.BRANCH); + mainBranch.setKey("master"); + underTest.insert(dbSession, mainBranch); + + BranchDto featureBranch = new BranchDto(); + featureBranch.setProjectUuid("U1"); + featureBranch.setUuid("U2"); + featureBranch.setBranchType(BranchType.SHORT); + featureBranch.setKeeType(BranchKeyType.BRANCH); + featureBranch.setKey("feature/foo"); + featureBranch.setMergeBranchUuid("U3"); + underTest.insert(dbSession, featureBranch); + + // select the feature branch + BranchDto loaded = underTest.selectByKey(dbSession, "U1", BranchKeyType.BRANCH, "feature/foo").get(); + assertThat(loaded.getUuid()).isEqualTo(featureBranch.getUuid()); + assertThat(loaded.getKey()).isEqualTo(featureBranch.getKey()); + assertThat(loaded.getProjectUuid()).isEqualTo(featureBranch.getProjectUuid()); + assertThat(loaded.getBranchType()).isEqualTo(featureBranch.getBranchType()); + assertThat(loaded.getKeeType()).isEqualTo(featureBranch.getKeeType()); + assertThat(loaded.getMergeBranchUuid()).isEqualTo(featureBranch.getMergeBranchUuid()); + assertThat(loaded.getPullRequestTitle()).isEqualTo(featureBranch.getPullRequestTitle()); + + // select a pull request with same key than the feature branch + assertThat(underTest.selectByKey(dbSession, "U1", BranchKeyType.PR, "feature/foo")).isEmpty(); + + // select a branch on another project with same branch name + assertThat(underTest.selectByKey(dbSession, "U3", BranchKeyType.BRANCH, "feature/foo")).isEmpty(); + } + +} diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDtoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDtoTest.java new file mode 100644 index 00000000000..53e2e216fd1 --- /dev/null +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDtoTest.java @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.component; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BranchDtoTest { + + private BranchDto underTest = new BranchDto(); + + @Test + public void isMain_is_true_if_branch_uuid_equals_project_uuid() { + underTest.setProjectUuid("U1"); + underTest.setUuid("U1"); + + assertThat(underTest.isMain()).isTrue(); + } + + @Test + public void isMain_is_false_if_branch_uuid_does_not_equal_project_uuid() { + underTest.setProjectUuid("U1"); + underTest.setUuid("U2"); + + assertThat(underTest.isMain()).isFalse(); + } +} diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java index 2050730e8fd..0f66805fdd4 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java @@ -202,7 +202,7 @@ public class ComponentDaoTest { public void get_by_key_on_disabled_component() { ComponentDto project = db.components().insertPrivateProject(p -> p.setEnabled(false)); - ComponentDto result = underTest.selectOrFailByKey(dbSession, project.getKey()); + ComponentDto result = underTest.selectOrFailByKey(dbSession, project.getDbKey()); assertThat(result.isEnabled()).isFalse(); } @@ -211,7 +211,7 @@ public class ComponentDaoTest { public void get_by_key_on_a_root_project() { ComponentDto project = db.components().insertPrivateProject(); - ComponentDto result = underTest.selectOrFailByKey(dbSession, project.getKey()); + ComponentDto result = underTest.selectOrFailByKey(dbSession, project.getDbKey()); assertThat(result.getDbKey()).isEqualTo(project.getDbKey()); assertThat(result.uuid()).isEqualTo(project.uuid()); @@ -225,13 +225,13 @@ public class ComponentDaoTest { ComponentDto project1 = db.components().insertPrivateProject(); ComponentDto project2 = db.components().insertPrivateProject(); - List results = underTest.selectByKeys(dbSession, asList(project1.getKey(), project2.getKey())); + List results = underTest.selectByKeys(dbSession, asList(project1.getDbKey(), project2.getDbKey())); assertThat(results) - .extracting(ComponentDto::uuid, ComponentDto::getKey) + .extracting(ComponentDto::uuid, ComponentDto::getDbKey) .containsExactlyInAnyOrder( - tuple(project1.uuid(), project1.getKey()), - tuple(project2.uuid(), project2.getKey())); + tuple(project1.uuid(), project1.getDbKey()), + tuple(project2.uuid(), project2.getDbKey())); assertThat(underTest.selectByKeys(dbSession, singletonList("unknown"))).isEmpty(); } @@ -244,10 +244,10 @@ public class ComponentDaoTest { List results = underTest.selectByIds(dbSession, asList(project1.getId(), project2.getId())); assertThat(results) - .extracting(ComponentDto::uuid, ComponentDto::getKey) + .extracting(ComponentDto::uuid, ComponentDto::getDbKey) .containsExactlyInAnyOrder( - tuple(project1.uuid(), project1.getKey()), - tuple(project2.uuid(), project2.getKey())); + tuple(project1.uuid(), project1.getDbKey()), + tuple(project2.uuid(), project2.getDbKey())); assertThat(underTest.selectByIds(dbSession, singletonList(0L))).isEmpty(); } @@ -260,10 +260,10 @@ public class ComponentDaoTest { List results = underTest.selectByUuids(dbSession, asList(project1.uuid(), project2.uuid())); assertThat(results) - .extracting(ComponentDto::uuid, ComponentDto::getKey) + .extracting(ComponentDto::uuid, ComponentDto::getDbKey) .containsExactlyInAnyOrder( - tuple(project1.uuid(), project1.getKey()), - tuple(project2.uuid(), project2.getKey())); + tuple(project1.uuid(), project1.getDbKey()), + tuple(project2.uuid(), project2.getDbKey())); assertThat(underTest.selectByUuids(dbSession, singletonList("unknown"))).isEmpty(); } @@ -276,7 +276,7 @@ public class ComponentDaoTest { List results = underTest.selectByUuids(dbSession, asList(project1.uuid(), project2.uuid())); assertThat(results) - .extracting(ComponentDto::getKey, ComponentDto::isEnabled) + .extracting(ComponentDto::getDbKey, ComponentDto::isEnabled) .containsExactlyInAnyOrder( tuple(project1.getDbKey(), true), tuple(project2.getDbKey(), false)); diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/property/PropertiesDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/property/PropertiesDaoTest.java index e3d4838ade8..8b0c455d92f 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/property/PropertiesDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/property/PropertiesDaoTest.java @@ -402,27 +402,6 @@ public class PropertiesDaoTest { .isEmpty(); } - @Test - public void select_component_properties_by_keys() throws Exception { - ComponentDto project = dbTester.components().insertPrivateProject(); - UserDto user = dbTester.users().insertUser(); - - String key = "key"; - String anotherKey = "anotherKey"; - insertProperties( - newGlobalPropertyDto().setKey(key), - newComponentPropertyDto(project).setKey(key), - newUserPropertyDto(user).setKey(key), - newComponentPropertyDto(project).setKey(anotherKey)); - - assertThat(underTest.selectPropertiesByKeysAndComponentId(session, newHashSet(key), project.getId())).extracting("key").containsOnly(key); - assertThat(underTest.selectPropertiesByKeysAndComponentId(session, newHashSet(key, anotherKey), project.getId())).extracting("key").containsOnly(key, anotherKey); - assertThat(underTest.selectPropertiesByKeysAndComponentId(session, newHashSet(key, anotherKey, "unknown"), project.getId())).extracting("key").containsOnly(key, anotherKey); - - assertThat(underTest.selectPropertiesByKeysAndComponentId(session, newHashSet("unknown"), project.getId())).isEmpty(); - assertThat(underTest.selectPropertiesByKeysAndComponentId(session, newHashSet(key), 123456789L)).isEmpty(); - } - @Test public void select_component_properties_by_ids() throws Exception { ComponentDto project = dbTester.components().insertPrivateProject(); diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v66/AddBranchColumnToProjectsTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v66/AddBranchColumnToProjectsTable.java index 713f7dab8ff..cb499371b99 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v66/AddBranchColumnToProjectsTable.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v66/AddBranchColumnToProjectsTable.java @@ -17,7 +17,6 @@ * 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.v66; import java.sql.SQLException; diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v66/CreateTableProjectBranches.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v66/CreateTableProjectBranches.java index f7884a01dcf..db40d988aec 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v66/CreateTableProjectBranches.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v66/CreateTableProjectBranches.java @@ -76,6 +76,10 @@ public class CreateTableProjectBranches extends DdlChange { .setColumnName("created_at") .setIsNullable(false) .build()) + .addColumn(BigIntegerColumnDef.newBigIntegerColumnDefBuilder() + .setColumnName("updated_at") + .setIsNullable(false) + .build()) .build() ); } diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v66/CreateTableProjectBranchesTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v66/CreateTableProjectBranchesTest.java index a960ef02b65..f8d74a0b115 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v66/CreateTableProjectBranchesTest.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v66/CreateTableProjectBranchesTest.java @@ -53,6 +53,7 @@ public class CreateTableProjectBranchesTest { db.assertColumnDefinition(TABLE, "merge_branch_uuid", Types.VARCHAR, 50, true); db.assertColumnDefinition(TABLE, "pull_request_title", Types.VARCHAR, 4000, true); db.assertColumnDefinition(TABLE, "created_at", Types.BIGINT, null, false); + db.assertColumnDefinition(TABLE, "updated_at", Types.BIGINT, null, false); db.assertPrimaryKey(TABLE, "pk_" + TABLE, "uuid"); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/ReportSubmitter.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/ReportSubmitter.java index aad44371d6f..e6f63e2ef84 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/ReportSubmitter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/ReportSubmitter.java @@ -87,8 +87,8 @@ public class ReportSubmitter { public CeTask submit(String organizationKey, String projectKey, @Nullable String projectBranch, @Nullable String projectName, Map characteristics, InputStream reportInput) { try (DbSession dbSession = dbClient.openSession(false)) { - String effectiveProjectKey = ComponentKeys.createKey(projectKey, projectBranch); OrganizationDto organizationDto = getOrganizationDtoOrFail(dbSession, organizationKey); + String effectiveProjectKey = ComponentKeys.createKey(projectKey, projectBranch); Optional opt = dbClient.componentDao().selectByKey(dbSession, effectiveProjectKey); ensureOrganizationIsConsistent(opt, organizationDto); ComponentDto project = opt.or(() -> createProject(dbSession, organizationDto, projectKey, projectBranch, projectName)); @@ -122,12 +122,13 @@ public class ReportSubmitter { } } - private ComponentDto createProject(DbSession dbSession, OrganizationDto organization, String projectKey, @Nullable String projectBranch, @Nullable String projectName) { + private ComponentDto createProject(DbSession dbSession, OrganizationDto organization, String projectKey, @Nullable String deprecatedBranch, @Nullable String projectName) { userSession.checkPermission(OrganizationPermission.PROVISION_PROJECTS, organization); Integer userId = userSession.getUserId(); + String effectiveProjectKey = ComponentKeys.createEffectiveKey(projectKey, deprecatedBranch); boolean wouldCurrentUserHaveScanPermission = permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate( - dbSession, organization.getUuid(), userId, projectBranch, projectKey, Qualifiers.PROJECT); + dbSession, organization.getUuid(), userId, effectiveProjectKey, Qualifiers.PROJECT); if (!wouldCurrentUserHaveScanPermission) { throw insufficientPrivilegesException(); } @@ -138,7 +139,7 @@ public class ReportSubmitter { .setOrganizationUuid(organization.getUuid()) .setKey(projectKey) .setName(StringUtils.defaultIfBlank(projectName, projectKey)) - .setBranch(projectBranch) + .setBranch(deprecatedBranch) .setQualifier(Qualifiers.PROJECT) .setPrivate(newProjectPrivate) .build(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolder.java index bb922d5e256..e86d1a7501c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolder.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolder.java @@ -20,6 +20,7 @@ package org.sonar.server.computation.task.projectanalysis.analysis; import java.util.Map; +import java.util.Optional; import javax.annotation.CheckForNull; import org.sonar.server.qualityprofile.QualityProfile; @@ -74,10 +75,28 @@ public interface AnalysisMetadataHolder { boolean isCrossProjectDuplicationEnabled(); /** + * Branch is present whatever the type of branch (long or short, main or not). However + * it is absent when analyzing a pull request. + * * @throws IllegalStateException if branch has not been set */ - @CheckForNull - String getBranch(); + Optional getBranch(); + + /** + * The project as represented by the main branch. It is used to load settings + * like Quality gates, webhooks and configuration. + * + * In case of analysis of main branch, the returned value is the main branch, + * so its uuid and key are the same in + * {@link org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder#getRoot(). + * + * In case of analysis of non-main branch or pull request, the returned value + * is the main branch. Its uuid and key are different than + * {@link org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder#getRoot(). + * + * @throws IllegalStateException if project has not been set + */ + Project getProject(); /** * @throws IllegalStateException if root component ref has not been set diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolderImpl.java index e03ddd2afcf..7b0a9dcbec0 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolderImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolderImpl.java @@ -21,6 +21,7 @@ package org.sonar.server.computation.task.projectanalysis.analysis; import com.google.common.collect.ImmutableMap; import java.util.Map; +import java.util.Optional; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.server.computation.util.InitializedProperty; @@ -37,7 +38,8 @@ public class AnalysisMetadataHolderImpl implements MutableAnalysisMetadataHolder private final InitializedProperty incrementalAnalysis = new InitializedProperty<>(); private final InitializedProperty baseProjectSnapshot = new InitializedProperty<>(); private final InitializedProperty crossProjectDuplicationEnabled = new InitializedProperty<>(); - private final InitializedProperty branch = new InitializedProperty<>(); + private final InitializedProperty branch = new InitializedProperty<>(); + private final InitializedProperty project = new InitializedProperty<>(); private final InitializedProperty rootComponentRef = new InitializedProperty<>(); private final InitializedProperty> qProfilesPerLanguage = new InitializedProperty<>(); private final InitializedProperty> pluginsByKey = new InitializedProperty<>(); @@ -134,16 +136,29 @@ public class AnalysisMetadataHolderImpl implements MutableAnalysisMetadataHolder } @Override - public MutableAnalysisMetadataHolder setBranch(@Nullable String branch) { + public MutableAnalysisMetadataHolder setBranch(@Nullable Branch branch) { checkState(!this.branch.isInitialized(), "Branch has already been set"); this.branch.setProperty(branch); return this; } @Override - public String getBranch() { + public Optional getBranch() { checkState(branch.isInitialized(), "Branch has not been set"); - return branch.getProperty(); + return Optional.ofNullable(branch.getProperty()); + } + + @Override + public MutableAnalysisMetadataHolder setProject(Project project) { + checkState(!this.project.isInitialized(), "Project has already been set"); + this.project.setProperty(project); + return this; + } + + @Override + public Project getProject() { + checkState(project.isInitialized(), "Project has not been set"); + return project.getProperty(); } @Override diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/Branch.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/Branch.java new file mode 100644 index 00000000000..7695ae14653 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/Branch.java @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.analysis; + +import java.util.Optional; +import javax.annotation.concurrent.Immutable; +import org.sonar.db.component.BranchType; +import org.sonar.server.computation.task.projectanalysis.component.ComponentKeyGenerator; + +@Immutable +public interface Branch extends ComponentKeyGenerator { + + BranchType getType(); + + boolean isMain(); + + /** + * Name can be empty when it's not known on the main branch + * (regular analysis without the branch parameters) + */ + Optional getName(); + + /** + * Whether the cross-project duplication tracker must be enabled + * or not. + */ + boolean supportsCrossProjectCpd(); +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/MutableAnalysisMetadataHolder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/MutableAnalysisMetadataHolder.java index 88214c7c596..624d16b58b9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/MutableAnalysisMetadataHolder.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/MutableAnalysisMetadataHolder.java @@ -58,7 +58,12 @@ public interface MutableAnalysisMetadataHolder extends AnalysisMetadataHolder { /** * @throws IllegalStateException if branch has already been set */ - MutableAnalysisMetadataHolder setBranch(@Nullable String branch); + MutableAnalysisMetadataHolder setBranch(@Nullable Branch branch); + + /** + * @throws IllegalStateException if project has already been set + */ + MutableAnalysisMetadataHolder setProject(Project project); /** * @throws IllegalStateException if root component ref has already been set diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/Project.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/Project.java new file mode 100644 index 00000000000..96d840423dc --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/Project.java @@ -0,0 +1,91 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.analysis; + +import javax.annotation.concurrent.Immutable; +import org.sonar.db.component.ComponentDto; +import org.sonar.server.computation.task.projectanalysis.component.Component; + +@Immutable +public class Project { + + private final String uuid; + private final String key; + private final String name; + + public Project(String uuid, String key, String name) { + this.uuid = uuid; + this.key = key; + this.name = name; + } + + /** + * Always links to a row that exists in database. + */ + public String getUuid() { + return uuid; + } + + /** + * Always links to a row that exists in database. + */ + public String getKey() { + return key; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Project project = (Project) o; + return uuid.equals(project.uuid); + } + + @Override + public int hashCode() { + return uuid.hashCode(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("Project{"); + sb.append("uuid='").append(uuid).append('\''); + sb.append(", key='").append(key).append('\''); + sb.append(", name='").append(name).append('\''); + sb.append('}'); + return sb.toString(); + } + + public static Project copyOf(Component component) { + return new Project(component.getUuid(), component.getKey(), component.getName()); + } + + public static Project copyOf(ComponentDto component) { + return new Project(component.uuid(), component.getDbKey(), component.name()); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/api/measurecomputer/MeasureComputerContextImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/api/measurecomputer/MeasureComputerContextImpl.java index e2a33711860..1e207837af2 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/api/measurecomputer/MeasureComputerContextImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/api/measurecomputer/MeasureComputerContextImpl.java @@ -35,7 +35,6 @@ import org.sonar.api.ce.measure.Measure; import org.sonar.api.ce.measure.MeasureComputer.MeasureComputerContext; import org.sonar.api.ce.measure.MeasureComputer.MeasureComputerDefinition; import org.sonar.api.ce.measure.Settings; -import org.sonar.api.config.Configuration; import org.sonar.core.issue.DefaultIssue; import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; import org.sonar.server.computation.task.projectanalysis.issue.ComponentIssuesRepository; @@ -97,20 +96,16 @@ public class MeasureComputerContextImpl implements MeasureComputerContext { @Override @CheckForNull public String getString(String key) { - return getComponentSettings().get(key).orElse(null); + return config.getConfiguration().get(key).orElse(null); } @Override public String[] getStringArray(String key) { - return getComponentSettings().getStringArray(key); + return config.getConfiguration().getStringArray(key); } }; } - private Configuration getComponentSettings() { - return config.getConfiguration(internalComponent); - } - @Override @CheckForNull public Measure getMeasure(String metric) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/BranchLoader.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/BranchLoader.java new file mode 100644 index 00000000000..1e5777bbd2a --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/BranchLoader.java @@ -0,0 +1,57 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.component; + +import javax.annotation.Nullable; +import org.sonar.api.utils.MessageException; +import org.sonar.scanner.protocol.output.ScannerReport; +import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolder; + +import static org.apache.commons.lang.StringUtils.trimToNull; + +public class BranchLoader { + + private final MutableAnalysisMetadataHolder metadataHolder; + private final BranchLoaderDelegate delegate; + + public BranchLoader(MutableAnalysisMetadataHolder metadataHolder) { + this(metadataHolder, null); + } + + public BranchLoader(MutableAnalysisMetadataHolder metadataHolder, @Nullable BranchLoaderDelegate delegate) { + this.metadataHolder = metadataHolder; + this.delegate = delegate; + } + + public void load(ScannerReport.Metadata metadata) { + String deprecatedBranch = trimToNull(metadata.getDeprecatedBranch()); + String branchName = trimToNull(metadata.getBranchName()); + + if (deprecatedBranch != null && branchName != null) { + throw MessageException.of("Properties sonar.branch and sonar.branch.name can't be set together"); + } + + if (delegate != null && deprecatedBranch == null) { + delegate.load(metadata); + } else { + metadataHolder.setBranch(new MainBranchImpl(deprecatedBranch)); + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/BranchLoaderDelegate.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/BranchLoaderDelegate.java new file mode 100644 index 00000000000..19aff4f1539 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/BranchLoaderDelegate.java @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.component; + +import org.sonar.api.ce.ComputeEngineSide; +import org.sonar.scanner.protocol.output.ScannerReport; + +@ComputeEngineSide +public interface BranchLoaderDelegate { + + void load(ScannerReport.Metadata metadata); + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/BranchPersisterDelegate.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/BranchPersisterDelegate.java new file mode 100644 index 00000000000..21ab94b98c5 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/BranchPersisterDelegate.java @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.component; + +import org.sonar.api.ce.ComputeEngineSide; +import org.sonar.db.DbSession; + +@ComputeEngineSide +public interface BranchPersisterDelegate { + + void persist(DbSession dbSession); + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/Component.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/Component.java index 0d2b65169d0..a2be3b3a097 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/Component.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/Component.java @@ -72,7 +72,9 @@ public interface Component { String getUuid(); /** - * Returns the component key + * Returns the component key as defined in database + * It may differ from keys listed in scanner report + * when analyzing a branch. */ String getKey(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentKeyGenerator.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentKeyGenerator.java new file mode 100644 index 00000000000..5f277aa6ae3 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentKeyGenerator.java @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.component; + +import javax.annotation.Nullable; +import org.sonar.scanner.protocol.output.ScannerReport; + +@FunctionalInterface +public interface ComponentKeyGenerator { + + String generateKey(ScannerReport.Component module, @Nullable ScannerReport.Component fileOrDir); + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilder.java new file mode 100644 index 00000000000..7627811ee37 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilder.java @@ -0,0 +1,204 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.component; + +import java.util.function.Function; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +import org.sonar.db.component.SnapshotDto; +import org.sonar.scanner.protocol.output.ScannerReport; +import org.sonar.scanner.protocol.output.ScannerReport.Component.FileStatus; +import org.sonar.server.computation.task.projectanalysis.analysis.Project; + +import static com.google.common.base.MoreObjects.firstNonNull; +import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.String.format; +import static org.apache.commons.lang.StringUtils.trimToNull; + +public class ComponentTreeBuilder { + + private static final String DEFAULT_PROJECT_VERSION = "not provided"; + + private final ComponentKeyGenerator keyGenerator; + /** + * Will supply the UUID for any component in the tree, given it's key. + *

+ * The String argument of the {@link Function#apply(Object)} method is the component's key. + *

+ */ + private final Function uuidSupplier; + + /** + * Will supply the {@link ScannerReport.Component} of all the components in the component tree as we crawl it from the + * root. + *

+ * The Integer argument of the {@link Function#apply(Object)} method is the component's ref. + *

+ */ + private final Function scannerComponentSupplier; + + private final Project project; + + @Nullable + private final SnapshotDto baseAnalysis; + + public ComponentTreeBuilder( + ComponentKeyGenerator keyGenerator, + Function uuidSupplier, + Function scannerComponentSupplier, + Project project, + @Nullable SnapshotDto baseAnalysis) { + + this.keyGenerator = keyGenerator; + this.uuidSupplier = uuidSupplier; + this.scannerComponentSupplier = scannerComponentSupplier; + this.project = project; + this.baseAnalysis = baseAnalysis; + } + + public Component buildProject(ScannerReport.Component project) { + return buildComponent(project, project); + } + + private Component[] buildChildren(ScannerReport.Component component, ScannerReport.Component parentModule) { + return component.getChildRefList() + .stream() + .map(componentRef -> buildComponent(scannerComponentSupplier.apply(componentRef), parentModule)) + .toArray(Component[]::new); + } + + private ComponentImpl buildComponent(ScannerReport.Component component, ScannerReport.Component closestModule) { + switch (component.getType()) { + case PROJECT: + String projectKey = keyGenerator.generateKey(component, null); + String uuid = uuidSupplier.apply(projectKey); + return ComponentImpl.builder(Component.Type.PROJECT) + .setUuid(uuid) + .setKey(projectKey) + .setName(nameOfProject(component)) + .setStatus(convertStatus(component.getStatus())) + .setDescription(trimToNull(component.getDescription())) + .setReportAttributes(createAttributesBuilder(component) + .setVersion(createProjectVersion(component)) + .build()) + .addChildren(buildChildren(component, component)) + .build(); + + case MODULE: + String moduleKey = keyGenerator.generateKey(component, null); + return ComponentImpl.builder(Component.Type.MODULE) + .setUuid(uuidSupplier.apply(moduleKey)) + .setKey(moduleKey) + .setName(nameOfOthers(component, moduleKey)) + .setStatus(convertStatus(component.getStatus())) + .setDescription(trimToNull(component.getDescription())) + .setReportAttributes(createAttributesBuilder(component).build()) + .addChildren(buildChildren(component, component)) + .build(); + + case DIRECTORY: + case FILE: + String key = keyGenerator.generateKey(closestModule, component); + return ComponentImpl.builder(convertDirOrFileType(component.getType())) + .setUuid(uuidSupplier.apply(key)) + .setKey(key) + .setName(nameOfOthers(component, key)) + .setStatus(convertStatus(component.getStatus())) + .setDescription(trimToNull(component.getDescription())) + .setReportAttributes(createAttributesBuilder(component).build()) + .setFileAttributes(createFileAttributes(component)) + .addChildren(buildChildren(component, closestModule)) + .build(); + + default: + throw new IllegalArgumentException(format("Unsupported component type '%s'", component.getType())); + } + } + + private static Component.Status convertStatus(FileStatus status) { + switch(status) { + case ADDED: + return Component.Status.ADDED; + case SAME: + return Component.Status.SAME; + case CHANGED: + return Component.Status.CHANGED; + case UNAVAILABLE: + return Component.Status.UNAVAILABLE; + case UNRECOGNIZED: + default: + throw new IllegalArgumentException("Unsupported ComponentType value " + status); + } + } + + private String nameOfProject(ScannerReport.Component component) { + String name = trimToNull(component.getName()); + if (name != null) { + return name; + } + return project.getName(); + } + + private static String nameOfOthers(ScannerReport.Component reportComponent, String defaultName) { + String name = trimToNull(reportComponent.getName()); + return name == null ? defaultName : name; + } + + private String createProjectVersion(ScannerReport.Component component) { + String version = trimToNull(component.getVersion()); + if (version != null) { + return version; + } + if (baseAnalysis != null) { + return firstNonNull(baseAnalysis.getVersion(), DEFAULT_PROJECT_VERSION); + } + return DEFAULT_PROJECT_VERSION; + } + + private static ReportAttributes.Builder createAttributesBuilder(ScannerReport.Component component) { + return ReportAttributes.newBuilder(component.getRef()) + .setVersion(trimToNull(component.getVersion())) + .setPath(trimToNull(component.getPath())); + } + + @CheckForNull + private static FileAttributes createFileAttributes(ScannerReport.Component component) { + if (component.getType() != ScannerReport.Component.ComponentType.FILE) { + return null; + } + + checkArgument(component.getLines() > 0, "File '%s' has no line", component.getPath()); + return new FileAttributes( + component.getIsTest(), + trimToNull(component.getLanguage()), + component.getLines()); + } + + private static Component.Type convertDirOrFileType(ScannerReport.Component.ComponentType type) { + switch (type) { + case DIRECTORY: + return Component.Type.DIRECTORY; + case FILE: + return Component.Type.FILE; + default: + throw new IllegalArgumentException("Unsupported ComponentType value " + type); + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/UuidFactory.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentUuidFactory.java similarity index 69% rename from server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/UuidFactory.java rename to server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentUuidFactory.java index 393e79f99ae..6cf3c218706 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/UuidFactory.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentUuidFactory.java @@ -27,23 +27,21 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; -public class UuidFactory { +public class ComponentUuidFactory { + private final Map uuidsByKey = new HashMap<>(); - public UuidFactory(DbClient dbClient, String rootKey) { - try (DbSession dbSession = dbClient.openSession(false)) { - List components = dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, rootKey); - for (ComponentDto componentDto : components) { - uuidsByKey.put(componentDto.getDbKey(), componentDto.uuid()); - } + public ComponentUuidFactory(DbClient dbClient, DbSession dbSession, String rootKey) { + List components = dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, rootKey); + for (ComponentDto dto : components) { + uuidsByKey.put(dto.getDbKey(), dto.uuid()); } } /** - * Get UUID from database if it exists, else generate a new one + * Get UUID from database if it exists, otherwise generate a new one. */ public String getOrCreateForKey(String key) { - String uuid = uuidsByKey.get(key); - return (uuid == null) ? Uuids.create() : uuid; + return uuidsByKey.computeIfAbsent(key, k -> Uuids.create()); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ConfigurationRepository.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ConfigurationRepository.java index 1dd33a4f4e3..c6bab6f4bf6 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ConfigurationRepository.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ConfigurationRepository.java @@ -21,12 +21,8 @@ package org.sonar.server.computation.task.projectanalysis.component; import org.sonar.api.config.Configuration; -/** - * Repository of component settings. - */ public interface ConfigurationRepository { - /** - * Returns the configuration for the specified Component. - */ - Configuration getConfiguration(Component component); + + Configuration getConfiguration(); + } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ConfigurationRepositoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ConfigurationRepositoryImpl.java index 80489e4730a..cbc8df1bb9e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ConfigurationRepositoryImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ConfigurationRepositoryImpl.java @@ -19,38 +19,28 @@ */ package org.sonar.server.computation.task.projectanalysis.component; -import java.util.Collection; -import java.util.Map; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import org.sonar.api.config.Configuration; +import org.sonar.ce.queue.CeTask; import org.sonar.ce.settings.ProjectConfigurationFactory; -import org.sonar.server.util.cache.CacheLoader; -import org.sonar.server.util.cache.MemoryCache; /** * Repository of component settings implementation based on a memory cache. */ public class ConfigurationRepositoryImpl implements ConfigurationRepository { - private final ProjectConfigurationFactory projectConfigurationFactory; - private final MemoryCache cache = new MemoryCache<>(new CacheLoader() { - @Override - public Configuration load(String key) { - return projectConfigurationFactory.newProjectConfiguration(key); - } + private final Supplier configuration; - @Override - public Map loadAll(Collection keys) { - throw new UnsupportedOperationException("loadAll is not supported"); - } - }); - - public ConfigurationRepositoryImpl(ProjectConfigurationFactory projectSettingsFactory) { - this.projectConfigurationFactory = projectSettingsFactory; + public ConfigurationRepositoryImpl(CeTask ceTask, ProjectConfigurationFactory f) { + // project key is loaded from task because + // analysisMetadataHolder.getProject() may be not set yet + // when the first ComputationSteps are executed. + this.configuration = Suppliers.memoize(() -> f.newProjectConfiguration(ceTask.getComponentKey())); } @Override - public Configuration getConfiguration(Component component) { - return cache.get(component.getKey()); + public Configuration getConfiguration() { + return configuration.get(); } - } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/MainBranchImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/MainBranchImpl.java new file mode 100644 index 00000000000..6893a43d7d9 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/MainBranchImpl.java @@ -0,0 +1,82 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.component; + +import java.util.Optional; +import javax.annotation.Nullable; +import org.sonar.api.utils.MessageException; +import org.sonar.core.component.ComponentKeys; +import org.sonar.db.component.BranchType; +import org.sonar.scanner.protocol.output.ScannerReport; +import org.sonar.server.computation.task.projectanalysis.analysis.Branch; + +import static java.lang.String.format; +import static org.apache.commons.lang.StringUtils.isEmpty; +import static org.apache.commons.lang.StringUtils.trimToNull; + +/** + * The default (and legacy) implementation of {@link Branch}. It is used + * when scanner is configured with parameter "sonar.branch". + * A legacy branch is implemented as a fork of the project, so any branch + * is considered as "main". + */ +public class MainBranchImpl implements Branch { + + @Nullable + private final String branchName; + + public MainBranchImpl(@Nullable String name) { + this.branchName = name; + if (name != null && !ComponentKeys.isValidBranch(name)) { + throw MessageException.of(format("\"%s\" is not a valid branch name. " + + "Allowed characters are alphanumeric, '-', '_', '.' and '/'.", name)); + } + } + + @Override + public BranchType getType() { + return BranchType.LONG; + } + + @Override + public boolean isMain() { + return true; + } + + @Override + public Optional getName() { + return Optional.ofNullable(branchName); + } + + @Override + public boolean supportsCrossProjectCpd() { + // only on regular project, not on branches + return branchName == null; + } + + @Override + public String generateKey(ScannerReport.Component module, @Nullable ScannerReport.Component fileOrDir) { + String moduleWithBranch = ComponentKeys.createKey(module.getKey(), branchName); + if (fileOrDir == null || isEmpty(fileOrDir.getPath())) { + return moduleWithBranch; + } + return ComponentKeys.createEffectiveKey(moduleWithBranch, trimToNull(fileOrDir.getPath())); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/TreeRootHolder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/TreeRootHolder.java index 3ef387a802a..24c57476a2d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/TreeRootHolder.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/TreeRootHolder.java @@ -24,7 +24,7 @@ package org.sonar.server.computation.task.projectanalysis.component; */ public interface TreeRootHolder { /** - * The root of the tree of Component representing the component in the current ScannerReport. + * The root of the tree, for example the project or the portfolio. * * @throws IllegalStateException if the holder is empty (ie. there is no root yet) */ diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulator.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulator.java index 7b9392619c1..d4d2b580bda 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulator.java @@ -33,9 +33,10 @@ import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetada import org.sonar.server.computation.task.projectanalysis.api.posttask.PostProjectAnalysisTasksExecutor; import org.sonar.server.computation.task.projectanalysis.batch.BatchReportDirectoryHolderImpl; import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderImpl; +import org.sonar.server.computation.task.projectanalysis.component.BranchLoader; +import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepositoryImpl; import org.sonar.server.computation.task.projectanalysis.component.DbIdsRepositoryImpl; import org.sonar.server.computation.task.projectanalysis.component.DisabledComponentsHolderImpl; -import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepositoryImpl; import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderImpl; import org.sonar.server.computation.task.projectanalysis.duplication.CrossProjectDuplicationStatusHolderImpl; import org.sonar.server.computation.task.projectanalysis.duplication.DuplicationMeasures; @@ -161,7 +162,6 @@ public final class ProjectAnalysisTaskContainerPopulator implements ContainerPop ActiveRulesHolderImpl.class, MeasureComputersHolderImpl.class, MutableTaskResultHolderImpl.class, - BatchReportReaderImpl.class, // repositories @@ -243,6 +243,7 @@ public final class ProjectAnalysisTaskContainerPopulator implements ContainerPop // views ViewIndex.class, + BranchLoader.class, MeasureToMeasureDto.class, // webhooks diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/duplication/CrossProjectDuplicationStatusHolderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/duplication/CrossProjectDuplicationStatusHolderImpl.java index da9c3a1b6e8..4a463e16c69 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/duplication/CrossProjectDuplicationStatusHolderImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/duplication/CrossProjectDuplicationStatusHolderImpl.java @@ -19,11 +19,13 @@ */ package org.sonar.server.computation.task.projectanalysis.duplication; +import java.util.Optional; import javax.annotation.CheckForNull; import org.picocontainer.Startable; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; +import org.sonar.server.computation.task.projectanalysis.analysis.Branch; import static com.google.common.base.Preconditions.checkState; @@ -47,13 +49,14 @@ public class CrossProjectDuplicationStatusHolderImpl implements CrossProjectDupl @Override public void start() { - boolean crossProjectDuplicationIsEnabledInReport = analysisMetadataHolder.isCrossProjectDuplicationEnabled(); - boolean branchIsUsed = analysisMetadataHolder.getBranch() != null; - if (crossProjectDuplicationIsEnabledInReport && !branchIsUsed) { + boolean enabledInReport = analysisMetadataHolder.isCrossProjectDuplicationEnabled(); + Optional branch = analysisMetadataHolder.getBranch(); + boolean supportedByBranch = !branch.isPresent() || branch.get().supportsCrossProjectCpd(); + if (enabledInReport && supportedByBranch) { LOGGER.debug("Cross project duplication is enabled"); this.enabled = true; } else { - if (!crossProjectDuplicationIsEnabledInReport) { + if (!enabledInReport) { LOGGER.debug("Cross project duplication is disabled because it's disabled in the analysis report"); } else { LOGGER.debug("Cross project duplication is disabled because of a branch is used"); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/DefaultAssignee.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/DefaultAssignee.java index 9fccec30442..c9d41d231d4 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/DefaultAssignee.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/DefaultAssignee.java @@ -28,7 +28,6 @@ import org.sonar.db.DbSession; import org.sonar.db.user.UserDto; import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; -import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; import static org.sonar.api.CoreProperties.DEFAULT_ISSUE_ASSIGNEE; @@ -41,16 +40,14 @@ public class DefaultAssignee { private static final Logger LOG = Loggers.get(DefaultAssignee.class); private final DbClient dbClient; - private final TreeRootHolder treeRootHolder; private final ConfigurationRepository configRepository; private final AnalysisMetadataHolder analysisMetadataHolder; private boolean loaded = false; private String login = null; - public DefaultAssignee(DbClient dbClient, TreeRootHolder treeRootHolder, ConfigurationRepository configRepository, AnalysisMetadataHolder analysisMetadataHolder) { + public DefaultAssignee(DbClient dbClient, ConfigurationRepository configRepository, AnalysisMetadataHolder analysisMetadataHolder) { this.dbClient = dbClient; - this.treeRootHolder = treeRootHolder; this.configRepository = configRepository; this.analysisMetadataHolder = analysisMetadataHolder; } @@ -60,7 +57,7 @@ public class DefaultAssignee { if (loaded) { return login; } - String configuredLogin = configRepository.getConfiguration(treeRootHolder.getRoot()).get(DEFAULT_ISSUE_ASSIGNEE).orElse(null); + String configuredLogin = configRepository.getConfiguration().get(DEFAULT_ISSUE_ASSIGNEE).orElse(null); if (!Strings.isNullOrEmpty(configuredLogin) && isValidLogin(configuredLogin)) { this.login = configuredLogin; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/filter/IssueFilter.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/filter/IssueFilter.java index d45d0338b3b..63746de05c9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/filter/IssueFilter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/filter/IssueFilter.java @@ -30,7 +30,6 @@ import org.sonar.api.utils.log.Loggers; import org.sonar.core.issue.DefaultIssue; import org.sonar.server.computation.task.projectanalysis.component.Component; import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; -import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Strings.isNullOrEmpty; @@ -49,8 +48,8 @@ public class IssueFilter { private final List exclusionPatterns; private final List inclusionPatterns; - public IssueFilter(TreeRootHolder treeRootHolder, ConfigurationRepository configRepository) { - Configuration config = configRepository.getConfiguration(treeRootHolder.getRoot()); + public IssueFilter(ConfigurationRepository configRepository) { + Configuration config = configRepository.getConfiguration(); this.exclusionPatterns = loadPatterns(PATTERNS_MULTICRITERIA_EXCLUSION_KEY, config); this.inclusionPatterns = loadPatterns(PATTERNS_MULTICRITERIA_INCLUSION_KEY, config); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/qualitygate/QualityGateServiceImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/qualitygate/QualityGateServiceImpl.java index a524141097c..2ad4bb9fb39 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/qualitygate/QualityGateServiceImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/qualitygate/QualityGateServiceImpl.java @@ -34,7 +34,7 @@ public class QualityGateServiceImpl implements QualityGateService { private final DbClient dbClient; private final MetricRepository metricRepository; - public QualityGateServiceImpl(DbClient dbClient, final MetricRepository metricRepository) { + public QualityGateServiceImpl(DbClient dbClient, MetricRepository metricRepository) { this.dbClient = dbClient; this.metricRepository = metricRepository; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStep.java index 5592ff9d7cd..edc9921eb6f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStep.java @@ -19,10 +19,11 @@ */ package org.sonar.server.computation.task.projectanalysis.step; -import com.google.common.base.Optional; -import java.util.Objects; -import java.util.function.Function; +import java.util.Optional; +import java.util.stream.Stream; import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +import org.sonar.core.component.ComponentKeys; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.SnapshotDto; @@ -32,13 +33,14 @@ import org.sonar.server.computation.task.projectanalysis.analysis.Analysis; import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolder; import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader; import org.sonar.server.computation.task.projectanalysis.component.Component; -import org.sonar.server.computation.task.projectanalysis.component.ComponentRootBuilder; +import org.sonar.server.computation.task.projectanalysis.component.ComponentKeyGenerator; +import org.sonar.server.computation.task.projectanalysis.component.ComponentTreeBuilder; +import org.sonar.server.computation.task.projectanalysis.component.ComponentUuidFactory; import org.sonar.server.computation.task.projectanalysis.component.MutableTreeRootHolder; -import org.sonar.server.computation.task.projectanalysis.component.UuidFactory; import org.sonar.server.computation.task.step.ComputationStep; -import static com.google.common.base.Preconditions.checkState; -import static org.sonar.core.component.ComponentKeys.createKey; +import static org.apache.commons.lang.StringUtils.isEmpty; +import static org.apache.commons.lang.StringUtils.trimToNull; /** * Populates the {@link MutableTreeRootHolder} and {@link MutableAnalysisMetadataHolder} from the {@link BatchReportReader} @@ -50,7 +52,8 @@ public class BuildComponentTreeStep implements ComputationStep { private final MutableTreeRootHolder treeRootHolder; private final MutableAnalysisMetadataHolder analysisMetadataHolder; - public BuildComponentTreeStep(DbClient dbClient, BatchReportReader reportReader, MutableTreeRootHolder treeRootHolder, MutableAnalysisMetadataHolder analysisMetadataHolder) { + public BuildComponentTreeStep(DbClient dbClient, BatchReportReader reportReader, + MutableTreeRootHolder treeRootHolder, MutableAnalysisMetadataHolder analysisMetadataHolder) { this.dbClient = dbClient; this.reportReader = reportReader; this.treeRootHolder = treeRootHolder; @@ -64,64 +67,52 @@ public class BuildComponentTreeStep implements ComputationStep { @Override public void execute() { - String branch = analysisMetadataHolder.getBranch(); - ScannerReport.Component reportProject = reportReader.readComponent(analysisMetadataHolder.getRootComponentRef()); - String projectKey = createKey(reportProject.getKey(), branch); - UuidFactory uuidFactory = new UuidFactory(dbClient, projectKey); - try (DbSession dbSession = dbClient.openSession(false)) { - BaseAnalysisSupplier baseAnalysisSupplier = new BaseAnalysisSupplier(dbClient, dbSession); - ComponentRootBuilder rootBuilder = new ComponentRootBuilder(branch, - uuidFactory::getOrCreateForKey, + ScannerReport.Component reportProject = reportReader.readComponent(analysisMetadataHolder.getRootComponentRef()); + ComponentKeyGenerator keyGenerator = loadKeyGenerator(); + + // root key of branch, not necessarily of project + String rootKey = keyGenerator.generateKey(reportProject, null); + + // loads the UUIDs from database. If they don't exist, then generate new ones + ComponentUuidFactory componentUuidFactory = new ComponentUuidFactory(dbClient, dbSession, rootKey); + + String rootUuid = componentUuidFactory.getOrCreateForKey(rootKey); + SnapshotDto baseAnalysis = loadBaseAnalysis(dbSession, rootUuid); + + ComponentTreeBuilder builder = new ComponentTreeBuilder(keyGenerator, + componentUuidFactory::getOrCreateForKey, reportReader::readComponent, - () -> dbClient.componentDao().selectByKey(dbSession, projectKey), - baseAnalysisSupplier); - Component project = rootBuilder.build(reportProject, projectKey); + analysisMetadataHolder.getProject(), + baseAnalysis); + Component project = builder.buildProject(reportProject); + treeRootHolder.setRoot(project); - analysisMetadataHolder.setBaseAnalysis(toAnalysis(baseAnalysisSupplier.apply(project.getUuid()))); + analysisMetadataHolder.setBaseAnalysis(toAnalysis(baseAnalysis)); } } - /** - * A supplier of the base analysis of the project (if it exists) that will cache the retrieved SnapshotDto and - * implement a sanity check to ensure it is always call with the same UUID value (since it's the project's UUID, it - * is unique for a whole task). - */ - private static final class BaseAnalysisSupplier implements Function> { - private final DbClient dbClient; - private final DbSession dbSession; - private String projectUuid = null; - private Optional cache = null; - - private BaseAnalysisSupplier(DbClient dbClient, DbSession dbSession) { - this.dbClient = dbClient; - this.dbSession = dbSession; - } + private ComponentKeyGenerator loadKeyGenerator() { + return Stream.of(analysisMetadataHolder.getBranch(), Optional.of(new DefaultKeyGenerator())) + // TODO pull request generator will be added here + .filter(Optional::isPresent) + .flatMap(x -> x.map(Stream::of).orElseGet(Stream::empty)) + .findFirst() + .get(); + } - @Override - public Optional apply(String projectUuid) { - if (this.cache == null) { - this.cache = Optional.fromNullable( - dbClient.snapshotDao().selectAnalysisByQuery( - dbSession, - new SnapshotQuery() - .setComponentUuid(projectUuid) - .setIsLast(true))); - this.projectUuid = projectUuid; - } else { - checkState( - Objects.equals(this.projectUuid, projectUuid), - "BaseAnalysisSupplier called with different project uuid values. First one was %s but current one is %s", - this.projectUuid, projectUuid); - } - return this.cache; - } + @CheckForNull + private SnapshotDto loadBaseAnalysis(DbSession dbSession, String rootUuid) { + return dbClient.snapshotDao().selectAnalysisByQuery( + dbSession, + new SnapshotQuery() + .setComponentUuid(rootUuid) + .setIsLast(true)); } @CheckForNull - private static Analysis toAnalysis(Optional snapshotDto) { - if (snapshotDto.isPresent()) { - SnapshotDto dto = snapshotDto.get(); + private static Analysis toAnalysis(@Nullable SnapshotDto dto) { + if (dto != null) { return new Analysis.Builder() .setId(dto.getId()) .setUuid(dto.getUuid()) @@ -131,4 +122,14 @@ public class BuildComponentTreeStep implements ComputationStep { return null; } + private static class DefaultKeyGenerator implements ComponentKeyGenerator { + @Override + public String generateKey(ScannerReport.Component module, @Nullable ScannerReport.Component fileOrDir) { + String moduleKey = module.getKey(); + if (fileOrDir == null || isEmpty(fileOrDir.getPath())) { + return moduleKey; + } + return ComponentKeys.createEffectiveKey(moduleKey, trimToNull(fileOrDir.getPath())); + } + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadPeriodsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadPeriodsStep.java index ee17fcfcd13..27c193a6276 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadPeriodsStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadPeriodsStep.java @@ -93,7 +93,7 @@ public class LoadPeriodsStep implements ComputationStep { PeriodResolver periodResolver = new PeriodResolver(dbClient, session, projectDto.get().uuid(), analysisMetadataHolder.getAnalysisDate(), isReportType ? projectOrView.getReportAttributes().getVersion() : null); - Configuration config = configRepository.getConfiguration(projectOrView); + Configuration config = configRepository.getConfiguration(); Period period = periodResolver.resolve(config); // SONAR-4700 Add a past snapshot only if it exists if (period != null) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadQualityGateStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadQualityGateStep.java index ca1d5588d54..3248e2c7804 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadQualityGateStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadQualityGateStep.java @@ -20,22 +20,16 @@ package org.sonar.server.computation.task.projectanalysis.step; import com.google.common.base.Optional; -import org.apache.commons.lang.StringUtils; import org.sonar.api.config.Configuration; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; -import org.sonar.server.computation.task.projectanalysis.component.Component; import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; -import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit; -import org.sonar.server.computation.task.projectanalysis.component.DepthTraversalTypeAwareCrawler; -import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; -import org.sonar.server.computation.task.projectanalysis.component.TypeAwareVisitorAdapter; import org.sonar.server.computation.task.projectanalysis.qualitygate.MutableQualityGateHolder; import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGate; import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGateService; import org.sonar.server.computation.task.step.ComputationStep; -import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER; +import static org.apache.commons.lang.StringUtils.isBlank; /** * This step retrieves the QualityGate and stores it in @@ -46,14 +40,12 @@ public class LoadQualityGateStep implements ComputationStep { private static final String PROPERTY_QUALITY_GATE = "sonar.qualitygate"; - private final TreeRootHolder treeRootHolder; private final ConfigurationRepository configRepository; private final QualityGateService qualityGateService; private final MutableQualityGateHolder qualityGateHolder; - public LoadQualityGateStep(TreeRootHolder treeRootHolder, ConfigurationRepository settingsRepository, + public LoadQualityGateStep(ConfigurationRepository settingsRepository, QualityGateService qualityGateService, MutableQualityGateHolder qualityGateHolder) { - this.treeRootHolder = treeRootHolder; this.configRepository = settingsRepository; this.qualityGateService = qualityGateService; this.qualityGateHolder = qualityGateHolder; @@ -61,22 +53,11 @@ public class LoadQualityGateStep implements ComputationStep { @Override public void execute() { - new DepthTraversalTypeAwareCrawler( - new TypeAwareVisitorAdapter(CrawlerDepthLimit.PROJECT, PRE_ORDER) { - @Override - public void visitProject(Component project) { - executeForProject(project); - } - }).visit(treeRootHolder.getRoot()); - } - - private void executeForProject(Component project) { - String projectKey = project.getKey(); - Configuration config = configRepository.getConfiguration(project); + Configuration config = configRepository.getConfiguration(); String qualityGateSetting = config.get(PROPERTY_QUALITY_GATE).orElse(null); - if (StringUtils.isBlank(qualityGateSetting)) { - LOGGER.debug("No quality gate is configured for project " + projectKey); + if (isBlank(qualityGateSetting)) { + LOGGER.debug("No quality gate is configured"); qualityGateHolder.setNoQualityGate(); return; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStep.java index 664fb463b95..e5f5f6bf33b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStep.java @@ -25,13 +25,16 @@ import java.util.List; import java.util.Optional; import javax.annotation.CheckForNull; import javax.annotation.Nullable; +import org.apache.commons.lang.StringUtils; import org.sonar.api.utils.MessageException; import org.sonar.ce.queue.CeTask; +import org.sonar.core.component.ComponentKeys; import org.sonar.core.platform.PluginInfo; import org.sonar.core.platform.PluginRepository; import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.component.ComponentDto; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.QProfileDto; import org.sonar.scanner.protocol.output.ScannerReport; @@ -39,18 +42,18 @@ import org.sonar.scanner.protocol.output.ScannerReport.Metadata.Plugin; import org.sonar.scanner.protocol.output.ScannerReport.Metadata.QProfile; import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolder; import org.sonar.server.computation.task.projectanalysis.analysis.Organization; +import org.sonar.server.computation.task.projectanalysis.analysis.Project; import org.sonar.server.computation.task.projectanalysis.analysis.ScannerPlugin; import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader; +import org.sonar.server.computation.task.projectanalysis.component.BranchLoader; import org.sonar.server.computation.task.step.ComputationStep; -import org.sonar.server.organization.BillingValidations; -import org.sonar.server.organization.BillingValidations.BillingValidationsException; -import org.sonar.server.organization.BillingValidationsProxy; import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.qualityprofile.QualityProfile; +import static java.util.stream.Collectors.toMap; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Maps.transformValues; import static java.lang.String.format; -import static java.util.stream.Collectors.toMap; import static org.apache.commons.lang.StringUtils.isNotEmpty; import static org.sonar.core.util.stream.MoreCollectors.toList; @@ -58,50 +61,73 @@ import static org.sonar.core.util.stream.MoreCollectors.toList; * Feed analysis metadata holder with metadata from the analysis report. */ public class LoadReportAnalysisMetadataHolderStep implements ComputationStep { - private final CeTask ceTask; private final BatchReportReader reportReader; - private final MutableAnalysisMetadataHolder mutableAnalysisMetadataHolder; + private final MutableAnalysisMetadataHolder analysisMetadata; private final DefaultOrganizationProvider defaultOrganizationProvider; private final DbClient dbClient; - private final BillingValidations billingValidations; + private final BranchLoader branchLoader; private final PluginRepository pluginRepository; - public LoadReportAnalysisMetadataHolderStep(CeTask ceTask, BatchReportReader reportReader, MutableAnalysisMetadataHolder mutableAnalysisMetadataHolder, - DefaultOrganizationProvider defaultOrganizationProvider, DbClient dbClient, BillingValidationsProxy billingValidations, PluginRepository pluginRepository) { + public LoadReportAnalysisMetadataHolderStep(CeTask ceTask, BatchReportReader reportReader, MutableAnalysisMetadataHolder analysisMetadata, + DefaultOrganizationProvider defaultOrganizationProvider, DbClient dbClient, BranchLoader branchLoader, PluginRepository pluginRepository) { this.ceTask = ceTask; this.reportReader = reportReader; - this.mutableAnalysisMetadataHolder = mutableAnalysisMetadataHolder; + this.analysisMetadata = analysisMetadata; this.defaultOrganizationProvider = defaultOrganizationProvider; this.dbClient = dbClient; - this.billingValidations = billingValidations; + this.branchLoader = branchLoader; this.pluginRepository = pluginRepository; } @Override public void execute() { ScannerReport.Metadata reportMetadata = reportReader.readMetadata(); - mutableAnalysisMetadataHolder.setAnalysisDate(reportMetadata.getAnalysisDate()); - checkProjectKeyConsistency(reportMetadata); + loadMetadata(reportMetadata); + Organization organization = loadOrganization(reportMetadata); + loadProject(reportMetadata, organization); + loadIncrementalMode(reportMetadata); + loadQualityProfiles(reportMetadata, organization); + branchLoader.load(reportMetadata); + } + + private void loadMetadata(ScannerReport.Metadata reportMetadata) { + analysisMetadata.setAnalysisDate(reportMetadata.getAnalysisDate()); + analysisMetadata.setRootComponentRef(reportMetadata.getRootComponentRef()); + analysisMetadata.setCrossProjectDuplicationEnabled(reportMetadata.getCrossProjectDuplicationActivated()); + } + + private void loadProject(ScannerReport.Metadata reportMetadata, Organization organization) { + String reportProjectKey = projectKeyFromReport(reportMetadata); + checkProjectKeyConsistency(reportProjectKey); + ComponentDto dto = toProject(reportProjectKey); + if (!dto.getOrganizationUuid().equals(organization.getUuid())) { + throw MessageException.of(format("Project is not in the expected organization: %s", organization.getKey())); + } + if (dto.getMainBranchProjectUuid() != null) { + throw MessageException.of("Project should not reference a branch"); + } + analysisMetadata.setProject(new Project(dto.uuid(), dto.getDbKey(), dto.name())); + } + + private Organization loadOrganization(ScannerReport.Metadata reportMetadata) { Organization organization = toOrganization(ceTask.getOrganizationUuid()); checkOrganizationKeyConsistency(reportMetadata, organization); - checkOrganizationCanExecuteAnalysis(organization); - checkQualityProfilesConsistency(reportMetadata, organization); + analysisMetadata.setOrganization(organization); + return organization; + } - mutableAnalysisMetadataHolder.setRootComponentRef(reportMetadata.getRootComponentRef()); - mutableAnalysisMetadataHolder.setBranch(isNotEmpty(reportMetadata.getBranch()) ? reportMetadata.getBranch() : null); - mutableAnalysisMetadataHolder.setCrossProjectDuplicationEnabled(reportMetadata.getCrossProjectDuplicationActivated()); - mutableAnalysisMetadataHolder.setIncrementalAnalysis(reportMetadata.getIncremental()); - mutableAnalysisMetadataHolder.setQProfilesByLanguage(reportMetadata.getQprofilesPerLanguage().values().stream() + private void loadQualityProfiles(ScannerReport.Metadata reportMetadata, Organization organization) { + checkQualityProfilesConsistency(reportMetadata, organization); + analysisMetadata.setQProfilesByLanguage(reportMetadata.getQprofilesPerLanguage().values().stream() .collect(toMap( QProfile::getLanguage, qp -> new QualityProfile(qp.getKey(), qp.getName(), qp.getLanguage(), new Date(qp.getRulesUpdatedAt()))))); - mutableAnalysisMetadataHolder.setScannerPluginsByKey(reportMetadata.getPluginsByKey().values().stream() + analysisMetadata.setScannerPluginsByKey(reportMetadata.getPluginsByKey().values().stream() .collect(toMap( Plugin::getKey, p -> new ScannerPlugin(p.getKey(), getBasePluginKey(p), p.getUpdatedAt())))); - mutableAnalysisMetadataHolder.setOrganization(organization); } @CheckForNull @@ -115,6 +141,10 @@ public class LoadReportAnalysisMetadataHolderStep implements ComputationStep { return pluginInfo.getBasePlugin(); } + private void loadIncrementalMode(ScannerReport.Metadata reportMetadata) { + analysisMetadata.setIncrementalAnalysis(reportMetadata.getIncremental()); + } + /** * Check that the Quality profiles sent by scanner correctly relate to the project organization. */ @@ -134,8 +164,7 @@ public class LoadReportAnalysisMetadataHolderStep implements ComputationStep { } } - private void checkProjectKeyConsistency(ScannerReport.Metadata reportMetadata) { - String reportProjectKey = projectKeyFromReport(reportMetadata); + private void checkProjectKeyConsistency(String reportProjectKey) { String componentKey = ceTask.getComponentKey(); if (componentKey == null) { throw MessageException.of(format( @@ -168,14 +197,6 @@ public class LoadReportAnalysisMetadataHolderStep implements ComputationStep { } } - private void checkOrganizationCanExecuteAnalysis(Organization organization) { - try { - billingValidations.checkOnProjectAnalysis(new BillingValidations.Organization(organization.getKey(), organization.getUuid())); - } catch (BillingValidationsException e) { - throw MessageException.of(e.getMessage()); - } - } - private String resolveReportOrganizationKey(@Nullable String organizationKey) { if (reportBelongsToDefaultOrganization(organizationKey)) { return defaultOrganizationProvider.get().getKey(); @@ -190,14 +211,23 @@ public class LoadReportAnalysisMetadataHolderStep implements ComputationStep { private Organization toOrganization(String organizationUuid) { try (DbSession dbSession = dbClient.openSession(false)) { Optional organizationDto = dbClient.organizationDao().selectByUuid(dbSession, organizationUuid); - checkState(organizationDto.isPresent(), "Organization with uuid '{}' can't be found", organizationUuid); + checkState(organizationDto.isPresent(), "Organization with uuid '%s' can't be found", organizationUuid); return Organization.from(organizationDto.get()); } } + private ComponentDto toProject(String projectKey) { + try (DbSession dbSession = dbClient.openSession(false)) { + com.google.common.base.Optional opt = dbClient.componentDao().selectByKey(dbSession, projectKey); + checkState(opt.isPresent(), "Project with key '%s' can't be found", projectKey); + return opt.get(); + } + } + private static String projectKeyFromReport(ScannerReport.Metadata reportMetadata) { - if (isNotEmpty(reportMetadata.getBranch())) { - return reportMetadata.getProjectKey() + ":" + reportMetadata.getBranch(); + String deprecatedBranch = reportMetadata.getDeprecatedBranch(); + if (StringUtils.isNotEmpty(deprecatedBranch)) { + return ComponentKeys.createKey(reportMetadata.getProjectKey(), deprecatedBranch); } return reportMetadata.getProjectKey(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PersistComponentsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PersistComponentsStep.java index 985b2f60fb7..7961ca9f410 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PersistComponentsStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PersistComponentsStep.java @@ -26,7 +26,9 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Function; +import javax.annotation.CheckForNull; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang.StringUtils; import org.sonar.api.resources.Qualifiers; @@ -38,6 +40,8 @@ import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentUpdateDto; import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; +import org.sonar.server.computation.task.projectanalysis.analysis.Branch; +import org.sonar.server.computation.task.projectanalysis.component.BranchPersisterDelegate; import org.sonar.server.computation.task.projectanalysis.component.Component; import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit; import org.sonar.server.computation.task.projectanalysis.component.DbIdsRepositoryImpl; @@ -50,6 +54,7 @@ import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolde import org.sonar.server.computation.task.step.ComputationStep; import static com.google.common.collect.FluentIterable.from; +import static java.util.Optional.ofNullable; import static org.sonar.db.component.ComponentDto.UUID_PATH_OF_ROOT; import static org.sonar.db.component.ComponentDto.UUID_PATH_SEPARATOR; import static org.sonar.db.component.ComponentDto.formatUuidPathFromParent; @@ -66,16 +71,26 @@ public class PersistComponentsStep implements ComputationStep { private final System2 system2; private final MutableDisabledComponentsHolder disabledComponentsHolder; private final AnalysisMetadataHolder analysisMetadataHolder; + @Nullable + private final BranchPersisterDelegate branchPersister; public PersistComponentsStep(DbClient dbClient, TreeRootHolder treeRootHolder, MutableDbIdsRepository dbIdsRepository, System2 system2, MutableDisabledComponentsHolder disabledComponentsHolder, AnalysisMetadataHolder analysisMetadataHolder) { + this(dbClient, treeRootHolder, dbIdsRepository, system2, disabledComponentsHolder, analysisMetadataHolder, null); + } + + public PersistComponentsStep(DbClient dbClient, TreeRootHolder treeRootHolder, + MutableDbIdsRepository dbIdsRepository, System2 system2, + MutableDisabledComponentsHolder disabledComponentsHolder, AnalysisMetadataHolder analysisMetadataHolder, + @Nullable BranchPersisterDelegate branchPersister) { this.dbClient = dbClient; this.treeRootHolder = treeRootHolder; this.dbIdsRepository = dbIdsRepository; this.system2 = system2; this.disabledComponentsHolder = disabledComponentsHolder; this.analysisMetadataHolder = analysisMetadataHolder; + this.branchPersister = branchPersister; } @Override @@ -86,6 +101,8 @@ public class PersistComponentsStep implements ComputationStep { @Override public void execute() { try (DbSession dbSession = dbClient.openSession(false)) { + ofNullable(branchPersister).ifPresent(p -> p.persist(dbSession)); + String projectUuid = treeRootHolder.getRoot().getUuid(); // safeguard, reset all rows to b-changed=false @@ -93,9 +110,11 @@ public class PersistComponentsStep implements ComputationStep { Map existingDtosByKeys = indexExistingDtosByKey(dbSession); boolean isRootPrivate = isRootPrivate(treeRootHolder.getRoot(), existingDtosByKeys); + String mainBranchProjectUuid = loadProjectUuidOfMainBranch(); + // Insert or update the components in database. They are removed from existingDtosByKeys // at the same time. - new PathAwareCrawler<>(new PersistComponentStepsVisitor(existingDtosByKeys, dbSession)) + new PathAwareCrawler<>(new PersistComponentStepsVisitor(existingDtosByKeys, dbSession, mainBranchProjectUuid)) .visit(treeRootHolder.getRoot()); disableRemainingComponents(dbSession, existingDtosByKeys.values()); @@ -105,6 +124,19 @@ public class PersistComponentsStep implements ComputationStep { } } + /** + * See {@link ComponentDto#mainBranchProjectUuid} : value is null on main branches, otherwise it is + * the uuid of the main branch. + */ + @CheckForNull + private String loadProjectUuidOfMainBranch() { + Optional branch = analysisMetadataHolder.getBranch(); + if (branch.isPresent() && !branch.get().isMain()) { + return analysisMetadataHolder.getProject().getUuid(); + } + return null; + } + private void disableRemainingComponents(DbSession dbSession, Collection dtos) { Set uuids = dtos.stream() .filter(ComponentDto::isEnabled) @@ -144,8 +176,10 @@ public class PersistComponentsStep implements ComputationStep { private final Map existingComponentDtosByKey; private final DbSession dbSession; + @Nullable + private final String mainBranchProjectUuid; - public PersistComponentStepsVisitor(Map existingComponentDtosByKey, DbSession dbSession) { + PersistComponentStepsVisitor(Map existingComponentDtosByKey, DbSession dbSession, @Nullable String mainBranchProjectUuid) { super( CrawlerDepthLimit.LEAVES, PRE_ORDER, @@ -169,6 +203,7 @@ public class PersistComponentsStep implements ComputationStep { }); this.existingComponentDtosByKey = existingComponentDtosByKey; this.dbSession = dbSession; + this.mainBranchProjectUuid = mainBranchProjectUuid; } @Override @@ -250,141 +285,143 @@ public class PersistComponentsStep implements ComputationStep { private void addToCache(Component component, ComponentDto componentDto) { dbIdsRepository.setComponentId(component, componentDto.getId()); } - } - public ComponentDto createForProject(Component project) { - ComponentDto res = createBase(project); + public ComponentDto createForProject(Component project) { + ComponentDto res = createBase(project); - res.setScope(Scopes.PROJECT); - res.setQualifier(Qualifiers.PROJECT); - res.setName(project.getName()); - res.setLongName(res.name()); - res.setDescription(project.getDescription()); + res.setScope(Scopes.PROJECT); + res.setQualifier(Qualifiers.PROJECT); + res.setName(project.getName()); + res.setLongName(res.name()); + res.setDescription(project.getDescription()); - res.setProjectUuid(res.uuid()); - res.setRootUuid(res.uuid()); - res.setUuidPath(UUID_PATH_OF_ROOT); - res.setModuleUuidPath(UUID_PATH_SEPARATOR + res.uuid() + UUID_PATH_SEPARATOR); + res.setProjectUuid(res.uuid()); + res.setRootUuid(res.uuid()); + res.setUuidPath(UUID_PATH_OF_ROOT); + res.setModuleUuidPath(UUID_PATH_SEPARATOR + res.uuid() + UUID_PATH_SEPARATOR); - return res; - } + return res; + } - public ComponentDto createForModule(Component module, PathAwareVisitor.Path path) { - ComponentDto res = createBase(module); + public ComponentDto createForModule(Component module, PathAwareVisitor.Path path) { + ComponentDto res = createBase(module); - res.setScope(Scopes.PROJECT); - res.setQualifier(Qualifiers.MODULE); - res.setName(module.getName()); - res.setLongName(res.name()); - res.setPath(module.getReportAttributes().getPath()); - res.setDescription(module.getDescription()); + res.setScope(Scopes.PROJECT); + res.setQualifier(Qualifiers.MODULE); + res.setName(module.getName()); + res.setLongName(res.name()); + res.setPath(module.getReportAttributes().getPath()); + res.setDescription(module.getDescription()); - setRootAndParentModule(res, path); + setRootAndParentModule(res, path); - return res; - } + return res; + } - public ComponentDto createForDirectory(Component directory, PathAwareVisitor.Path path) { - ComponentDto res = createBase(directory); + public ComponentDto createForDirectory(Component directory, PathAwareVisitor.Path path) { + ComponentDto res = createBase(directory); - res.setScope(Scopes.DIRECTORY); - res.setQualifier(Qualifiers.DIRECTORY); - res.setName(directory.getReportAttributes().getPath()); - res.setLongName(directory.getReportAttributes().getPath()); - res.setPath(directory.getReportAttributes().getPath()); + res.setScope(Scopes.DIRECTORY); + res.setQualifier(Qualifiers.DIRECTORY); + res.setName(directory.getReportAttributes().getPath()); + res.setLongName(directory.getReportAttributes().getPath()); + res.setPath(directory.getReportAttributes().getPath()); - setParentModuleProperties(res, path); + setParentModuleProperties(res, path); - return res; - } + return res; + } - public ComponentDto createForFile(Component file, PathAwareVisitor.Path path) { - ComponentDto res = createBase(file); + public ComponentDto createForFile(Component file, PathAwareVisitor.Path path) { + ComponentDto res = createBase(file); - res.setScope(Scopes.FILE); - res.setQualifier(getFileQualifier(file)); - res.setName(FilenameUtils.getName(file.getReportAttributes().getPath())); - res.setLongName(file.getReportAttributes().getPath()); - res.setPath(file.getReportAttributes().getPath()); - res.setLanguage(file.getFileAttributes().getLanguageKey()); + res.setScope(Scopes.FILE); + res.setQualifier(getFileQualifier(file)); + res.setName(FilenameUtils.getName(file.getReportAttributes().getPath())); + res.setLongName(file.getReportAttributes().getPath()); + res.setPath(file.getReportAttributes().getPath()); + res.setLanguage(file.getFileAttributes().getLanguageKey()); - setParentModuleProperties(res, path); + setParentModuleProperties(res, path); - return res; - } + return res; + } - private ComponentDto createForView(Component view) { - ComponentDto res = createBase(view); + private ComponentDto createForView(Component view) { + ComponentDto res = createBase(view); - res.setScope(Scopes.PROJECT); - res.setQualifier(view.getViewAttributes().getType().getQualifier()); - res.setName(view.getName()); - res.setDescription(view.getDescription()); - res.setLongName(res.name()); + res.setScope(Scopes.PROJECT); + res.setQualifier(view.getViewAttributes().getType().getQualifier()); + res.setName(view.getName()); + res.setDescription(view.getDescription()); + res.setLongName(res.name()); - res.setProjectUuid(res.uuid()); - res.setRootUuid(res.uuid()); - res.setUuidPath(UUID_PATH_OF_ROOT); - res.setModuleUuidPath(UUID_PATH_SEPARATOR + res.uuid() + UUID_PATH_SEPARATOR); + res.setProjectUuid(res.uuid()); + res.setRootUuid(res.uuid()); + res.setUuidPath(UUID_PATH_OF_ROOT); + res.setModuleUuidPath(UUID_PATH_SEPARATOR + res.uuid() + UUID_PATH_SEPARATOR); - return res; - } + return res; + } - private ComponentDto createForSubView(Component subView, PathAwareVisitor.Path path) { - ComponentDto res = createBase(subView); + private ComponentDto createForSubView(Component subView, PathAwareVisitor.Path path) { + ComponentDto res = createBase(subView); - res.setScope(Scopes.PROJECT); - res.setQualifier(Qualifiers.SUBVIEW); - res.setName(subView.getName()); - res.setDescription(subView.getDescription()); - res.setLongName(res.name()); - res.setCopyComponentUuid(subView.getSubViewAttributes().getOriginalViewUuid()); + res.setScope(Scopes.PROJECT); + res.setQualifier(Qualifiers.SUBVIEW); + res.setName(subView.getName()); + res.setDescription(subView.getDescription()); + res.setLongName(res.name()); + res.setCopyComponentUuid(subView.getSubViewAttributes().getOriginalViewUuid()); - setRootAndParentModule(res, path); + setRootAndParentModule(res, path); - return res; - } + return res; + } - private ComponentDto createForProjectView(Component projectView, PathAwareVisitor.Path path) { - ComponentDto res = createBase(projectView); + private ComponentDto createForProjectView(Component projectView, PathAwareVisitor.Path path) { + ComponentDto res = createBase(projectView); - res.setScope(Scopes.FILE); - res.setQualifier(Qualifiers.PROJECT); - res.setName(projectView.getName()); - res.setLongName(res.name()); - res.setCopyComponentUuid(projectView.getProjectViewAttributes().getProjectUuid()); + res.setScope(Scopes.FILE); + res.setQualifier(Qualifiers.PROJECT); + res.setName(projectView.getName()); + res.setLongName(res.name()); + res.setCopyComponentUuid(projectView.getProjectViewAttributes().getProjectUuid()); - setRootAndParentModule(res, path); + setRootAndParentModule(res, path); - return res; - } + return res; + } - private ComponentDto createBase(Component component) { - String componentKey = component.getKey(); - String componentUuid = component.getUuid(); - - ComponentDto componentDto = new ComponentDto(); - componentDto.setOrganizationUuid(analysisMetadataHolder.getOrganization().getUuid()); - componentDto.setUuid(componentUuid); - componentDto.setDbKey(componentKey); - componentDto.setDeprecatedKey(componentKey); - componentDto.setEnabled(true); - componentDto.setCreatedAt(new Date(system2.now())); - return componentDto; - } + private ComponentDto createBase(Component component) { + String componentKey = component.getKey(); + String componentUuid = component.getUuid(); - /** - * Applies to a node of type either MODULE, SUBVIEW, PROJECT_VIEW - */ - private static void setRootAndParentModule(ComponentDto res, PathAwareVisitor.Path path) { - ComponentDto rootDto = path.root().getDto(); - res.setRootUuid(rootDto.uuid()); - res.setProjectUuid(rootDto.uuid()); - - ComponentDto parentModule = path.parent().getDto(); - res.setUuidPath(formatUuidPathFromParent(parentModule)); - res.setModuleUuid(parentModule.uuid()); - res.setModuleUuidPath(parentModule.moduleUuidPath() + res.uuid() + UUID_PATH_SEPARATOR); + ComponentDto componentDto = new ComponentDto(); + componentDto.setOrganizationUuid(analysisMetadataHolder.getOrganization().getUuid()); + componentDto.setUuid(componentUuid); + componentDto.setDbKey(componentKey); + componentDto.setDeprecatedKey(componentKey); + componentDto.setMainBranchProjectUuid(mainBranchProjectUuid); + componentDto.setEnabled(true); + componentDto.setCreatedAt(new Date(system2.now())); + + return componentDto; + } + + /** + * Applies to a node of type either MODULE, SUBVIEW, PROJECT_VIEW + */ + private void setRootAndParentModule(ComponentDto res, PathAwareVisitor.Path path) { + ComponentDto rootDto = path.root().getDto(); + res.setRootUuid(rootDto.uuid()); + res.setProjectUuid(rootDto.uuid()); + + ComponentDto parentModule = path.parent().getDto(); + res.setUuidPath(formatUuidPathFromParent(parentModule)); + res.setModuleUuid(parentModule.uuid()); + res.setModuleUuidPath(parentModule.moduleUuidPath() + res.uuid() + UUID_PATH_SEPARATOR); + } } /** @@ -424,7 +461,7 @@ public class PersistComponentsStep implements ComputationStep { .copyFrom(target) .setBChanged(true); } - return Optional.ofNullable(update); + return ofNullable(update); } private static String getFileQualifier(Component component) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PurgeDatastoresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PurgeDatastoresStep.java index 677689f58a4..5f9026e824a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PurgeDatastoresStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PurgeDatastoresStep.java @@ -75,7 +75,7 @@ public class PurgeDatastoresStep implements ComputationStep { private void execute(Component root) { try (DbSession dbSession = dbClient.openSession(true)) { IdUuidPair idUuidPair = new IdUuidPair(dbIdsRepository.getComponentId(root), root.getUuid()); - projectCleaner.purge(dbSession, idUuidPair, configRepository.getConfiguration(root), disabledComponentsHolder.getUuids()); + projectCleaner.purge(dbSession, idUuidPair, configRepository.getConfiguration(), disabledComponentsHolder.getUuids()); dbSession.commit(); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStep.java index da8c73acd1d..d39e3c4021a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateEventsStep.java @@ -92,7 +92,7 @@ public class QualityGateEventsStep implements ComputationStep { } if (!baseMeasure.get().hasQualityGateStatus()) { - LOGGER.warn(String.format("Previous alterStatus for project %s is not a supported value. Can not compute Quality Gate event", project.getKey())); + LOGGER.warn(String.format("Previous Quality gate status for project %s is not a supported value. Can not compute Quality Gate event", project.getKey())); checkNewQualityGate(project, rawStatus); return; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java index 02a4df5f3da..975422d8b26 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java @@ -37,6 +37,7 @@ public class ReportComputationSteps extends AbstractComputationSteps { // Builds Component tree LoadReportAnalysisMetadataHolderStep.class, + VerifyBillingStep.class, BuildComponentTreeStep.class, ValidateProjectStep.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ValidateProjectStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ValidateProjectStep.java index 56dc9be618d..77417850dad 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ValidateProjectStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ValidateProjectStep.java @@ -126,7 +126,6 @@ public class ValidateProjectStep implements ComputationStep { public void visitProject(Component rawProject) { this.rawProject = rawProject; String rawProjectKey = rawProject.getKey(); - validateBranch(); validateIncremental(rawProjectKey); validateNotIncrementalAndFirstAnalysis(rawProjectKey); validateBatchKey(rawProject); @@ -140,6 +139,7 @@ public class ValidateProjectStep implements ComputationStep { private void validateRootIsProject(Optional baseProject) { if (baseProject.isPresent()) { ComponentDto componentDto = baseProject.get(); + // the scope field is verified for excluding the project copies generated by portfolios if (!Qualifiers.PROJECT.equals(componentDto.qualifier()) || !Scopes.PROJECT.equals(componentDto.scope())) { validationMessages.add(format("Component (uuid=%s, key=%s) is not a project", rawProject.getUuid(), rawProject.getKey())); } @@ -226,17 +226,6 @@ public class ValidateProjectStep implements ComputationStep { } } - private void validateBranch() { - String branch = analysisMetadataHolder.getBranch(); - if (branch == null) { - return; - } - if (!ComponentKeys.isValidBranch(branch)) { - validationMessages.add(format("\"%s\" is not a valid branch name. " - + "Allowed characters are alphanumeric, '-', '_', '.' and '/'.", branch)); - } - } - private Optional loadBaseComponent(String rawComponentKey) { ComponentDto baseComponent = baseModulesByKey.get(rawComponentKey); if (baseComponent == null) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/VerifyBillingStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/VerifyBillingStep.java new file mode 100644 index 00000000000..74c3cd39422 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/VerifyBillingStep.java @@ -0,0 +1,57 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.step; + +import org.sonar.api.utils.MessageException; +import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; +import org.sonar.server.computation.task.projectanalysis.analysis.Organization; +import org.sonar.server.computation.task.step.ComputationStep; +import org.sonar.server.organization.BillingValidations; +import org.sonar.server.organization.BillingValidationsProxy; + +/** + * Verify that organization can execute analysis + */ +public class VerifyBillingStep implements ComputationStep { + + private final AnalysisMetadataHolder analysisMetadata; + private final BillingValidations billingValidations; + + public VerifyBillingStep(AnalysisMetadataHolder analysisMetadata, BillingValidationsProxy billingValidations) { + this.analysisMetadata = analysisMetadata; + this.billingValidations = billingValidations; + } + + @Override + public void execute() { + try { + Organization organization = analysisMetadata.getOrganization(); + BillingValidations.Organization billingOrganization = new BillingValidations.Organization(organization.getKey(), organization.getUuid()); + billingValidations.checkOnProjectAnalysis(billingOrganization); + } catch (BillingValidations.BillingValidationsException e) { + throw MessageException.of(e.getMessage()); + } + } + + @Override + public String getDescription() { + return "Verify billing"; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookPostTask.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookPostTask.java index c66de9fd3ae..7b124b75699 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookPostTask.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookPostTask.java @@ -30,7 +30,6 @@ import org.sonar.api.utils.log.Loggers; import org.sonar.core.config.WebhookProperties; import org.sonar.core.util.stream.MoreCollectors; import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; -import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; import static java.lang.String.format; import static org.sonar.core.config.WebhookProperties.MAX_WEBHOOKS_PER_TYPE; @@ -39,16 +38,14 @@ public class WebhookPostTask implements PostProjectAnalysisTask { private static final Logger LOGGER = Loggers.get(WebhookPostTask.class); - private final TreeRootHolder rootHolder; private final ConfigurationRepository configRepository; private final WebhookPayloadFactory payloadFactory; private final WebhookCaller caller; private final WebhookDeliveryStorage deliveryStorage; - public WebhookPostTask(TreeRootHolder rootHolder, ConfigurationRepository settingsRepository, WebhookPayloadFactory payloadFactory, + public WebhookPostTask(ConfigurationRepository configRepository, WebhookPayloadFactory payloadFactory, WebhookCaller caller, WebhookDeliveryStorage deliveryStorage) { - this.rootHolder = rootHolder; - this.configRepository = settingsRepository; + this.configRepository = configRepository; this.payloadFactory = payloadFactory; this.caller = caller; this.deliveryStorage = deliveryStorage; @@ -56,7 +53,7 @@ public class WebhookPostTask implements PostProjectAnalysisTask { @Override public void finished(ProjectAnalysis analysis) { - Configuration config = configRepository.getConfiguration(rootHolder.getRoot()); + Configuration config = configRepository.getConfiguration(); Iterable webhookProps = Iterables.concat( getWebhookProperties(config, WebhookProperties.GLOBAL_KEY), diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java index 64c2277ead6..eb68407e8bd 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java @@ -20,12 +20,15 @@ package org.sonar.server.organization; +import javax.annotation.Nullable; + public class BillingValidationsProxyImpl implements BillingValidationsProxy { + @Nullable private final BillingValidationsExtension billingValidationsExtension; - public BillingValidationsProxyImpl(BillingValidationsExtension billingValidationsExtension) { - this.billingValidationsExtension = billingValidationsExtension; + public BillingValidationsProxyImpl(BillingValidationsExtension e) { + this.billingValidationsExtension = e; } // Used when no plugin is providing the extension diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateService.java b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateService.java index c6766c405b4..4456a521e79 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateService.java @@ -30,7 +30,6 @@ import javax.annotation.Nullable; import org.apache.commons.lang.StringUtils; import org.sonar.api.resources.Qualifiers; import org.sonar.api.server.ServerSide; -import org.sonar.core.component.ComponentKeys; import org.sonar.core.permission.ProjectPermissions; import org.sonar.db.DbClient; import org.sonar.db.DbSession; @@ -73,14 +72,12 @@ public class PermissionTemplateService { public boolean wouldUserHaveScanPermissionWithDefaultTemplate(DbSession dbSession, String organizationUuid, @Nullable Integer userId, - @Nullable String branch, String projectKey, - String qualifier) { + String projectKey, String qualifier) { if (userSession.hasPermission(OrganizationPermission.SCAN, organizationUuid)) { return true; } - String effectiveKey = ComponentKeys.createKey(projectKey, branch); - ComponentDto dto = new ComponentDto().setOrganizationUuid(organizationUuid).setDbKey(effectiveKey).setQualifier(qualifier); + ComponentDto dto = new ComponentDto().setOrganizationUuid(organizationUuid).setDbKey(projectKey).setQualifier(qualifier); PermissionTemplateDto template = findTemplate(dbSession, organizationUuid, dto); if (template == null) { return false; diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ws/BranchesAction.java b/server/sonar-server/src/main/java/org/sonar/server/project/ws/BranchesAction.java new file mode 100644 index 00000000000..83c6eee4a25 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/project/ws/BranchesAction.java @@ -0,0 +1,85 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.project.ws; + +import java.util.Collection; +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.web.UserRole; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.component.BranchDto; +import org.sonar.db.component.BranchKeyType; +import org.sonar.db.component.ComponentDto; +import org.sonar.server.user.UserSession; +import org.sonar.server.ws.WsUtils; +import org.sonarqube.ws.WsProjects; + +import static org.sonar.core.util.Protobuf.setNullable; + +public class BranchesAction implements ProjectsWsAction { + + private static final String PROJECT_PARAM = "project"; + + private final DbClient dbClient; + private final UserSession userSession; + + public BranchesAction(DbClient dbClient, UserSession userSession) { + this.dbClient = dbClient; + this.userSession = userSession; + } + + @Override + public void define(WebService.NewController context) { + WebService.NewAction action = context.createAction("branches") + .setSince("6.6") + .setHandler(this); + + action + .createParam(PROJECT_PARAM) + .setRequired(true); + } + + @Override + public void handle(Request request, Response response) throws Exception { + String projectKey = request.mandatoryParam(PROJECT_PARAM); + + try (DbSession dbSession = dbClient.openSession(false)) { + ComponentDto project = dbClient.componentDao().selectOrFailByKey(dbSession, projectKey); + userSession.checkComponentPermission(UserRole.USER, project); + Collection branches = dbClient.branchDao().selectByComponent(dbSession, project); + + WsProjects.BranchesWsResponse.Builder protobufResponse = WsProjects.BranchesWsResponse.newBuilder(); + branches.stream() + .filter(b -> b.getKeeType().equals(BranchKeyType.BRANCH)) + .forEach(b -> addToProtobuf(protobufResponse, b)); + WsUtils.writeProtobuf(protobufResponse.build(), request, response); + } + } + + private static void addToProtobuf(WsProjects.BranchesWsResponse.Builder response, BranchDto branch) { + WsProjects.BranchesWsResponse.Branch.Builder builder = response.addBranchesBuilder(); + setNullable(branch.getKey(), builder::setName); + builder.setIsMain(branch.isMain()); + builder.setType(WsProjects.BranchesWsResponse.BranchType.valueOf(branch.getBranchType().name())); + builder.build(); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ws/ProjectsWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/project/ws/ProjectsWsModule.java index 48ce49927e7..bb8379878d3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/project/ws/ProjectsWsModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/project/ws/ProjectsWsModule.java @@ -29,6 +29,7 @@ public class ProjectsWsModule extends Module { ProjectsWs.class, CreateAction.class, IndexAction.class, + BranchesAction.class, BulkDeleteAction.class, DeleteAction.class, UpdateKeyAction.class, diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/queue/ReportSubmitterTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/queue/ReportSubmitterTest.java index 931a9790968..6c947ae6501 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/queue/ReportSubmitterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/queue/ReportSubmitterTest.java @@ -58,7 +58,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; @@ -127,9 +126,9 @@ public class ReportSubmitterTest { mockSuccessfulPrepareSubmitCall(); ComponentDto project = newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setDbKey(PROJECT_KEY); when(componentUpdater.create(any(DbSession.class), any(NewComponent.class), eq(null))).thenReturn(project); - when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), anyInt(), anyString(), - eq(PROJECT_KEY), eq(Qualifiers.PROJECT))) - .thenReturn(true); + when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), anyInt(), eq(PROJECT_KEY), + eq(Qualifiers.PROJECT))) + .thenReturn(true); Map taskCharacteristics = new HashMap<>(); taskCharacteristics.put("incremental", "true"); @@ -183,9 +182,9 @@ public class ReportSubmitterTest { mockSuccessfulPrepareSubmitCall(); ComponentDto createdProject = newPrivateProjectDto(organization, PROJECT_UUID).setDbKey(PROJECT_KEY); when(componentUpdater.create(any(DbSession.class), any(NewComponent.class), eq(null))).thenReturn(createdProject); - when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(organization.getUuid()), anyInt(), anyString(), - eq(PROJECT_KEY), eq(Qualifiers.PROJECT))) - .thenReturn(true); + when( + permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(organization.getUuid()), anyInt(), eq(PROJECT_KEY), eq(Qualifiers.PROJECT))) + .thenReturn(true); when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), eq(organization.getUuid()), any(ComponentDto.class))).thenReturn(true); underTest.submit(organization.getKey(), PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}")); @@ -214,9 +213,9 @@ public class ReportSubmitterTest { mockSuccessfulPrepareSubmitCall(); ComponentDto createdProject = newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setDbKey(PROJECT_KEY); when(componentUpdater.create(any(DbSession.class), any(NewComponent.class), eq(null))).thenReturn(createdProject); - when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), anyInt(), anyString(), + when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), anyInt(), eq(PROJECT_KEY), eq(Qualifiers.PROJECT))) - .thenReturn(true); + .thenReturn(true); when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), eq(defaultOrganizationUuid), any(ComponentDto.class))).thenReturn(false); underTest.submit(defaultOrganizationKey, PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}")); @@ -233,9 +232,9 @@ public class ReportSubmitterTest { mockSuccessfulPrepareSubmitCall(); ComponentDto project = newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setDbKey(PROJECT_KEY); when(componentUpdater.create(any(DbSession.class), any(NewComponent.class), eq(null))).thenReturn(project); - when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), anyInt(), anyString(), + when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), anyInt(), eq(PROJECT_KEY), eq(Qualifiers.PROJECT))) - .thenReturn(true); + .thenReturn(true); underTest.submit(defaultOrganizationKey, PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}")); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisImplTest.java index 894ebcdc85f..bd7f6543c77 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisImplTest.java @@ -30,9 +30,9 @@ public class AnalysisImplTest { @Rule public ExpectedException thrown = ExpectedException.none(); - static final long ID = 10; - static final String UUID = "uuid "; - static final long CREATED_AT = 123456789L; + private static final long ID = 10; + private static final String UUID = "uuid "; + private static final long CREATED_AT = 123456789L; @Test public void build_snapshot() throws Exception { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolderImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolderImplTest.java index 707acbeaffb..9b956794b41 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolderImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolderImplTest.java @@ -23,6 +23,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.db.organization.OrganizationDto; +import org.sonar.server.computation.task.projectanalysis.component.MainBranchImpl; import static org.assertj.core.api.Assertions.assertThat; @@ -260,36 +261,55 @@ public class AnalysisMetadataHolderImplTest { public void set_branch() { AnalysisMetadataHolderImpl underTest = new AnalysisMetadataHolderImpl(); - underTest.setBranch("origin/master"); + underTest.setBranch(new MainBranchImpl("master")); - assertThat(underTest.getBranch()).isEqualTo("origin/master"); + assertThat(underTest.getBranch().get().getName()).hasValue("master"); } @Test - public void set_no_branch() { + public void getBranch_throws_ISE_when_holder_is_not_initialized() { + expectedException.expect(IllegalStateException.class); + expectedException.expectMessage("Branch has not been set"); + + new AnalysisMetadataHolderImpl().getBranch(); + } + + @Test + public void setBranch_throws_ISE_when_called_twice() { AnalysisMetadataHolderImpl underTest = new AnalysisMetadataHolderImpl(); + underTest.setBranch(new MainBranchImpl("master")); - underTest.setBranch(null); + expectedException.expect(IllegalStateException.class); + expectedException.expectMessage("Branch has already been set"); + underTest.setBranch(new MainBranchImpl("master")); + } + + @Test + public void set_and_get_project() { + AnalysisMetadataHolderImpl underTest = new AnalysisMetadataHolderImpl(); + + Project project = new Project("U", "K", "N"); + underTest.setProject(project); - assertThat(underTest.getBranch()).isNull(); + assertThat(underTest.getProject()).isSameAs(project); } @Test - public void getBranch_throws_ISE_when_holder_is_not_initialized() { + public void getProject_throws_ISE_when_holder_is_not_initialized() { expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Branch has not been set"); + expectedException.expectMessage("Project has not been set"); - new AnalysisMetadataHolderImpl().getBranch(); + new AnalysisMetadataHolderImpl().getProject(); } @Test - public void setBranch_throws_ISE_when_called_twice() { + public void setProject_throws_ISE_when_called_twice() { AnalysisMetadataHolderImpl underTest = new AnalysisMetadataHolderImpl(); - underTest.setBranch("origin/master"); + underTest.setProject(new Project("U", "K", "N")); expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Branch has already been set"); - underTest.setBranch("origin/master"); + expectedException.expectMessage("Project has already been set"); + underTest.setProject(new Project("U", "K", "N")); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolderRule.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolderRule.java index 96edd5650ac..05977dbbd11 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolderRule.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/AnalysisMetadataHolderRule.java @@ -21,6 +21,7 @@ package org.sonar.server.computation.task.projectanalysis.analysis; import java.util.Date; import java.util.Map; +import java.util.Optional; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.junit.rules.ExternalResource; @@ -46,7 +47,9 @@ public class AnalysisMetadataHolderRule extends ExternalResource implements Muta private final InitializedProperty crossProjectDuplicationEnabled = new InitializedProperty<>(); - private final InitializedProperty branch = new InitializedProperty<>(); + private final InitializedProperty branch = new InitializedProperty<>(); + + private final InitializedProperty project = new InitializedProperty<>(); private final InitializedProperty rootComponentRef = new InitializedProperty<>(); @@ -141,15 +144,27 @@ public class AnalysisMetadataHolderRule extends ExternalResource implements Muta } @Override - public AnalysisMetadataHolderRule setBranch(@Nullable String branch) { + public AnalysisMetadataHolderRule setBranch(@Nullable Branch branch) { this.branch.setProperty(branch); return this; } @Override - public String getBranch() { + public Optional getBranch() { checkState(branch.isInitialized(), "Branch has not been set"); - return branch.getProperty(); + return Optional.ofNullable(branch.getProperty()); + } + + @Override + public AnalysisMetadataHolderRule setProject(Project p) { + this.project.setProperty(p); + return this; + } + + @Override + public Project getProject() { + checkState(project.isInitialized(), "Project has not been set"); + return project.getProperty(); } @Override diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/MutableAnalysisMetadataHolderRule.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/MutableAnalysisMetadataHolderRule.java index a6c6ca21548..b425b7ce384 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/MutableAnalysisMetadataHolderRule.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/MutableAnalysisMetadataHolderRule.java @@ -20,6 +20,7 @@ package org.sonar.server.computation.task.projectanalysis.analysis; import java.util.Map; +import java.util.Optional; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.junit.rules.ExternalResource; @@ -35,8 +36,9 @@ public class MutableAnalysisMetadataHolderRule extends ExternalResource implemen } @Override - public MutableAnalysisMetadataHolder setOrganization(Organization organization) { - return delegate.setOrganization(organization); + public MutableAnalysisMetadataHolderRule setOrganization(Organization organization) { + delegate.setOrganization(organization); + return this; } @Override @@ -98,16 +100,27 @@ public class MutableAnalysisMetadataHolderRule extends ExternalResource implemen } @Override - public String getBranch() { + public Optional getBranch() { return delegate.getBranch(); } @Override - public MutableAnalysisMetadataHolderRule setBranch(@Nullable String branch) { + public MutableAnalysisMetadataHolderRule setBranch(Branch branch) { delegate.setBranch(branch); return this; } + @Override + public MutableAnalysisMetadataHolderRule setProject(@Nullable Project project) { + delegate.setProject(project); + return this; + } + + @Override + public Project getProject() { + return delegate.getProject(); + } + @Override public MutableAnalysisMetadataHolderRule setRootComponentRef(int rootComponentRef) { delegate.setRootComponentRef(rootComponentRef); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/ProjectTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/ProjectTest.java new file mode 100644 index 00000000000..46941834440 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/analysis/ProjectTest.java @@ -0,0 +1,65 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.analysis; + +import org.junit.Test; +import org.sonar.server.computation.task.projectanalysis.component.Component; +import org.sonar.server.computation.task.projectanalysis.component.ReportComponent; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT; + +public class ProjectTest { + @Test + public void test_bean() { + Project project = new Project("U1", "K1", "N1"); + + assertThat(project.getUuid()).isEqualTo("U1"); + assertThat(project.getKey()).isEqualTo("K1"); + assertThat(project.getName()).isEqualTo("N1"); + + assertThat(project.toString()).isEqualTo("Project{uuid='U1', key='K1', name='N1'}"); + } + + @Test + public void test_equals_and_hashCode() { + Project project1 = new Project("U1", "K1", "N1"); + Project project1bis = new Project("U1", "K1", "N1"); + Project project2 = new Project("U2", "K2", project1.getName() /* same name */); + + assertThat(project1.equals(project1)).isTrue(); + assertThat(project1.equals(project1bis)).isTrue(); + assertThat(project1.equals(project2)).isFalse(); + assertThat(project1.equals("U1")).isFalse(); + + assertThat(project1.hashCode()).isEqualTo(project1.hashCode()); + assertThat(project1.hashCode()).isEqualTo(project1bis.hashCode()); + } + + @Test + public void test_copyOf() { + Component root = ReportComponent.builder(PROJECT, 1).setKey("ROOT").build(); + + Project project = Project.copyOf(root); + assertThat(project.getUuid()).isEqualTo(root.getUuid()).isNotNull(); + assertThat(project.getKey()).isEqualTo(root.getKey()).isNotNull(); + assertThat(project.getName()).isEqualTo(root.getName()).isNotNull(); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/api/measurecomputer/MeasureComputerContextImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/api/measurecomputer/MeasureComputerContextImplTest.java index 533c19917e8..13d795ef5df 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/api/measurecomputer/MeasureComputerContextImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/api/measurecomputer/MeasureComputerContextImplTest.java @@ -107,7 +107,7 @@ public class MeasureComputerContextImplTest { public void get_string_settings() throws Exception { MapSettings serverSettings = new MapSettings(); serverSettings.setProperty("prop", "value"); - when(settingsRepository.getConfiguration(FILE_1)).thenReturn(serverSettings.asConfig()); + when(settingsRepository.getConfiguration()).thenReturn(serverSettings.asConfig()); MeasureComputerContextImpl underTest = newContext(FILE_1_REF); assertThat(underTest.getSettings().getString("prop")).isEqualTo("value"); @@ -118,7 +118,7 @@ public class MeasureComputerContextImplTest { public void get_string_array_settings() throws Exception { MapSettings serverSettings = new MapSettings(); serverSettings.setProperty("prop", "1,3.4,8,50"); - when(settingsRepository.getConfiguration(FILE_1)).thenReturn(serverSettings.asConfig()); + when(settingsRepository.getConfiguration()).thenReturn(serverSettings.asConfig()); MeasureComputerContextImpl underTest = newContext(FILE_1_REF); assertThat(underTest.getSettings().getStringArray("prop")).containsExactly("1", "3.4", "8", "50"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/BranchLoaderTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/BranchLoaderTest.java new file mode 100644 index 00000000000..f63cbd7183f --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/BranchLoaderTest.java @@ -0,0 +1,107 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.component; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.MessageException; +import org.sonar.scanner.protocol.output.ScannerReport; +import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; +import org.sonar.server.computation.task.projectanalysis.analysis.Branch; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + + +public class BranchLoaderTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Rule + public AnalysisMetadataHolderRule metadataHolder = new AnalysisMetadataHolderRule(); + + @Test + public void throw_ME_if_both_branch_properties_are_set() { + ScannerReport.Metadata metadata = ScannerReport.Metadata.newBuilder() + .setDeprecatedBranch("foo") + .setBranchName("bar") + .build(); + + expectedException.expect(MessageException.class); + expectedException.expectMessage("Properties sonar.branch and sonar.branch.name can't be set together"); + + new BranchLoader(metadataHolder).load(metadata); + } + + @Test + public void regular_analysis_of_project_is_enabled_if_delegate_is_absent() { + ScannerReport.Metadata metadata = ScannerReport.Metadata.newBuilder() + .build(); + + new BranchLoader(metadataHolder).load(metadata); + + assertThat(metadataHolder.getBranch()).isPresent(); + + Branch branch = metadataHolder.getBranch().get(); + assertThat(branch.isMain()).isTrue(); + assertThat(branch.getName()).isEmpty(); + } + + @Test + public void default_support_of_branches_is_enabled_if_delegate_is_absent() { + ScannerReport.Metadata metadata = ScannerReport.Metadata.newBuilder() + .setDeprecatedBranch("foo") + .build(); + + new BranchLoader(metadataHolder).load(metadata); + + assertThat(metadataHolder.getBranch()).isPresent(); + + Branch branch = metadataHolder.getBranch().get(); + assertThat(branch.isMain()).isTrue(); + assertThat(branch.getName()).hasValue("foo"); + } + + @Test + public void default_support_of_branches_is_enabled_if_delegate_is_present() { + ScannerReport.Metadata metadata = ScannerReport.Metadata.newBuilder() + .setDeprecatedBranch("foo") + .build(); + + FakeDelegate delegate = new FakeDelegate(); + new BranchLoader(metadataHolder, delegate).load(metadata); + + assertThat(metadataHolder.getBranch()).isPresent(); + + Branch branch = metadataHolder.getBranch().get(); + assertThat(branch.isMain()).isTrue(); + assertThat(branch.getName()).hasValue("foo"); + } + + private class FakeDelegate implements BranchLoaderDelegate { + Branch branch = mock(Branch.class); + + @Override + public void load(ScannerReport.Metadata metadata) { + metadataHolder.setBranch(branch); + } + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentFunctionsTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentFunctionsTest.java index 992f8deaaf1..797677c0cbe 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentFunctionsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentFunctionsTest.java @@ -29,12 +29,7 @@ import static org.sonar.server.computation.task.projectanalysis.component.Compon public class ComponentFunctionsTest { - public static final int SOME_INT = new Random().nextInt(); - - @Test(expected = NullPointerException.class) - public void toReportRef_throws_NPE_if_Component_is_null() { - toReportRef().apply(null); - } + private static final int SOME_INT = new Random().nextInt(); @Test(expected = IllegalStateException.class) public void toReportRef_throws_ISE_if_Component_has_no_ReportAttributes() { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentRootBuilderTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentRootBuilderTest.java deleted file mode 100644 index f4aefdbaf4c..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentRootBuilderTest.java +++ /dev/null @@ -1,545 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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.computation.task.projectanalysis.component; - -import com.google.common.base.Optional; -import com.google.common.base.Supplier; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.ExternalResource; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.SnapshotDto; -import org.sonar.scanner.protocol.output.ScannerReport; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; -import static org.sonar.scanner.protocol.output.ScannerReport.Component.newBuilder; -import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.DIRECTORY; -import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.FILE; -import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.MODULE; -import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.PROJECT; -import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.UNRECOGNIZED; -import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.UNSET; -import static org.sonar.server.computation.task.projectanalysis.component.ComponentRootBuilder.createFileAttributes; -import static org.sonar.server.computation.task.projectanalysis.component.ComponentRootBuilder.createOtherReportAttributes; -import static org.sonar.server.computation.task.projectanalysis.component.ComponentRootBuilder.createProjectReportAttributes; -import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER; - -public class ComponentRootBuilderTest { - - private static final Function SIMPLE_UUID_GENERATOR = (componentKey) -> componentKey + "_uuid"; - private static final String NO_BRANCH = null; - private static final String PROJECT_KEY = "this is the key"; - private static final String MODULE_KEY = "module key"; - private static final String DIRECTORY_PATH = "directory path"; - private static final String DIRECTORY_KEY = MODULE_KEY + ":" + DIRECTORY_PATH; - private static final String FILE_PATH = "file path"; - private static final String FILE_KEY = MODULE_KEY + ":" + FILE_PATH; - private static final ComponentDto PROJECT_DTO = new ComponentDto().setName("name in db"); - private static final Supplier> NO_COMPONENT_DTO_FOR_PROJECT = Optional::absent; - private static final Function> NO_BASEANALYSIS = (projectUuid) -> Optional.absent(); - private static final Supplier> COMPONENT_DTO_FOR_PROJECT = () -> Optional.of(PROJECT_DTO); - private static final EnumSet REPORT_TYPES = EnumSet.of( - PROJECT, MODULE, DIRECTORY, FILE); - private static final String PROJECT_UUID = "project uuid"; - private static final String DEFAULT_VERSION = "not provided"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public ScannerComponentProvider scannerComponentProvider = new ScannerComponentProvider(); - - private ComponentRootBuilder underTest = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, NO_COMPONENT_DTO_FOR_PROJECT, NO_BASEANALYSIS); - - @Test - public void build_throws_IAE_for_all_types_but_PROJECT_MODULE_DIRECTORY_FILE() { - Arrays.stream(ScannerReport.Component.ComponentType.values()) - .filter((type) -> type != UNRECOGNIZED) - .filter((type) -> !REPORT_TYPES.contains(type)) - .forEach( - (type) -> { - ScannerReport.Component component = newBuilder().setType(type).build(); - try { - underTest.build(component, "don't care"); - fail("Should have thrown a IllegalArgumentException"); - } catch (IllegalArgumentException e) { - assertThat(e).hasMessage("Unsupported component type '" + type + "'"); - } - }); - } - - @Test - public void name_of_project_is_name_in_Scanner_Component_when_set() { - String expected = "the name"; - Component root = underTest.build(newBuilder().setType(PROJECT).setName(expected).build(), PROJECT_KEY); - assertThat(root.getName()).isEqualTo(expected); - } - - @Test - public void name_of_project_is_name_in_Scanner_Component_when_set_even_if_there_is_a_ComponentDto() { - String expected = "the name"; - Component root = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, COMPONENT_DTO_FOR_PROJECT, NO_BASEANALYSIS) - .build(newBuilder().setType(PROJECT).setName(expected).build(), PROJECT_KEY); - assertThat(root.getName()).isEqualTo(expected); - } - - @Test - public void name_of_project_is_specified_key_when_name_is_unset_in_Scanner_Component_and_there_is_no_ComponentDto() { - Component root = underTest.build(newBuilder().setType(PROJECT).build(), PROJECT_KEY); - assertThat(root.getName()).isEqualTo(PROJECT_KEY); - } - - @Test - public void name_of_project_is_specified_key_when_name_is_empty_in_Scanner_Component_and_there_is_no_ComponentDto() { - Component root = underTest.build(newBuilder().setType(PROJECT).setName("").build(), PROJECT_KEY); - - assertThat(root.getName()).isEqualTo(PROJECT_KEY); - } - - @Test - public void name_of_project_is_name_of_ComponentDto_when_name_is_unset_in_Scanner_Component_and_there_is_a_ComponentDto() { - Component root = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, COMPONENT_DTO_FOR_PROJECT, NO_BASEANALYSIS) - .build(newBuilder().setType(PROJECT).build(), PROJECT_KEY); - - assertThat(root.getName()).isEqualTo(PROJECT_DTO.name()); - } - - @Test - public void name_of_project_is_name_of_ComponentDto_when_name_is_empty_in_Scanner_Component_and_there_is_a_ComponentDto() { - Component root = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, COMPONENT_DTO_FOR_PROJECT, NO_BASEANALYSIS) - .build(newBuilder().setType(PROJECT).setName("").build(), PROJECT_KEY); - - assertThat(root.getName()).isEqualTo(PROJECT_DTO.name()); - } - - @Test - public void name_of_module_directory_and_file_contains_branch_when_non_empty() { - ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(2).build(); - scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setKey(MODULE_KEY).addChildRef(3)); - scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setPath(DIRECTORY_PATH).addChildRef(4)); - scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setPath(FILE_PATH).setLines(1)); - - String branch = "BRANCH"; - ComponentRootBuilder builder = new ComponentRootBuilder(branch, SIMPLE_UUID_GENERATOR, scannerComponentProvider, NO_COMPONENT_DTO_FOR_PROJECT, NO_BASEANALYSIS); - - Component root = builder.build(project, PROJECT_KEY); - assertThat(root.getKey()).isEqualTo(PROJECT_KEY); - assertThat(root.getChildren()).hasSize(1); - Component module = root.getChildren().iterator().next(); - assertThat(module.getKey()).isEqualTo(MODULE_KEY + ":" + branch); - assertThat(module.getChildren()).hasSize(1); - Component directory = module.getChildren().iterator().next(); - assertThat(directory.getKey()).isEqualTo(module.getKey() + ":" + DIRECTORY_PATH); - assertThat(directory.getChildren()).hasSize(1); - Component file = directory.getChildren().iterator().next(); - assertThat(file.getKey()).isEqualTo(module.getKey() + ":" + FILE_PATH); - assertThat(file.getChildren()).isEmpty(); - } - - @Test - public void name_of_module_directory_and_file_is_key_of_Scanner_Component_when_name_is_unset() { - ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(2).build(); - scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setKey(MODULE_KEY).addChildRef(3)); - scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setPath(DIRECTORY_PATH).addChildRef(4)); - scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setPath(FILE_PATH).setLines(1)); - - Component root = underTest.build(project, PROJECT_KEY); - assertThat(root.getKey()).isEqualTo(PROJECT_KEY); - Component module = root.getChildren().iterator().next(); - assertThat(module.getName()).isEqualTo(MODULE_KEY); - Component directory = module.getChildren().iterator().next(); - assertThat(directory.getName()).isEqualTo(module.getKey() + ":" + DIRECTORY_PATH); - Component file = directory.getChildren().iterator().next(); - assertThat(file.getName()).isEqualTo(module.getKey() + ":" + FILE_PATH); - } - - @Test - public void name_of_module_directory_and_file_is_key_of_Scanner_Component_when_name_is_empty() { - ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).setName("").addChildRef(2).build(); - scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setKey(MODULE_KEY).setName("").addChildRef(3)); - scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setPath(DIRECTORY_PATH).setName("").addChildRef(4)); - scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setPath(FILE_PATH).setName("").setLines(1)); - - Component root = underTest.build(project, PROJECT_KEY); - assertThat(root.getKey()).isEqualTo(PROJECT_KEY); - Component module = root.getChildren().iterator().next(); - assertThat(module.getName()).isEqualTo(MODULE_KEY); - Component directory = module.getChildren().iterator().next(); - assertThat(directory.getName()).isEqualTo(module.getKey() + ":" + DIRECTORY_PATH); - Component file = directory.getChildren().iterator().next(); - assertThat(file.getName()).isEqualTo(module.getKey() + ":" + FILE_PATH); - } - - @Test - public void name_of_module_directory_and_files_includes_name_of_closest_module() { - ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(11).addChildRef(21).addChildRef(31).build(); - scannerComponentProvider.add(newBuilder().setRef(11).setType(MODULE).setKey("module 1").addChildRef(12).addChildRef(22).addChildRef(32)); - scannerComponentProvider.add(newBuilder().setRef(12).setType(MODULE).setKey("module 2").addChildRef(13).addChildRef(23).addChildRef(33)); - scannerComponentProvider.add(newBuilder().setRef(13).setType(MODULE).setKey("module 3").addChildRef(24).addChildRef(34)); - scannerComponentProvider.add(newBuilder().setRef(21).setType(DIRECTORY).setPath("directory in project").addChildRef(35)); - scannerComponentProvider.add(newBuilder().setRef(22).setType(DIRECTORY).setPath("directory in module 1").addChildRef(36)); - scannerComponentProvider.add(newBuilder().setRef(23).setType(DIRECTORY).setPath("directory in module 2").addChildRef(37)); - scannerComponentProvider.add(newBuilder().setRef(24).setType(DIRECTORY).setPath("directory in module 3").addChildRef(38)); - scannerComponentProvider.add(newBuilder().setRef(31).setType(FILE).setPath("file in project").setLines(1)); - scannerComponentProvider.add(newBuilder().setRef(32).setType(FILE).setPath("file in module 1").setLines(1)); - scannerComponentProvider.add(newBuilder().setRef(33).setType(FILE).setPath("file in module 2").setLines(1)); - scannerComponentProvider.add(newBuilder().setRef(34).setType(FILE).setPath("file in module 3").setLines(1)); - scannerComponentProvider.add(newBuilder().setRef(35).setType(FILE).setPath("file in directory in project").setLines(1)); - scannerComponentProvider.add(newBuilder().setRef(36).setType(FILE).setPath("file in directory in module 1").setLines(1)); - scannerComponentProvider.add(newBuilder().setRef(37).setType(FILE).setPath("file in directory in module 2").setLines(1)); - scannerComponentProvider.add(newBuilder().setRef(38).setType(FILE).setPath("file in directory in module 3").setLines(1)); - - Component root = underTest.build(project, PROJECT_KEY); - Map componentsByRef = indexComponentByRef(root); - assertThat(componentsByRef.get(11).getKey()).isEqualTo("module 1"); - assertThat(componentsByRef.get(12).getKey()).isEqualTo("module 2"); - assertThat(componentsByRef.get(13).getKey()).isEqualTo("module 3"); - assertThat(componentsByRef.get(21).getKey()).startsWith(PROJECT_KEY + ":"); - assertThat(componentsByRef.get(22).getKey()).startsWith("module 1" + ":"); - assertThat(componentsByRef.get(23).getKey()).startsWith("module 2" + ":"); - assertThat(componentsByRef.get(24).getKey()).startsWith("module 3" + ":"); - assertThat(componentsByRef.get(31).getKey()).startsWith(PROJECT_KEY + ":"); - assertThat(componentsByRef.get(32).getKey()).startsWith("module 1" + ":"); - assertThat(componentsByRef.get(33).getKey()).startsWith("module 2" + ":"); - assertThat(componentsByRef.get(34).getKey()).startsWith("module 3" + ":"); - assertThat(componentsByRef.get(35).getKey()).startsWith(PROJECT_KEY + ":"); - assertThat(componentsByRef.get(36).getKey()).startsWith("module 1" + ":"); - assertThat(componentsByRef.get(37).getKey()).startsWith("module 2" + ":"); - assertThat(componentsByRef.get(38).getKey()).startsWith("module 3" + ":"); - } - - @Test - public void version_of_project_is_set_to_default_value_when_unset_in_Scanner_Component_and_no_base_analysis() { - ScannerReport.Component project = newBuilder().setType(PROJECT).build(); - - ComponentRootBuilder builder = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, - NO_COMPONENT_DTO_FOR_PROJECT, this::noBaseAnalysisButValidateProjectUuidArgument); - - Component root = builder.build(project, PROJECT_KEY); - assertThat(root.getReportAttributes().getVersion()).isEqualTo(DEFAULT_VERSION); - } - - @Test - public void version_of_project_is_set_to_default_value_when_empty_in_Scanner_Component_and_no_base_analysis() { - ScannerReport.Component project = newBuilder().setType(PROJECT).setVersion("").build(); - - ComponentRootBuilder builder = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, - NO_COMPONENT_DTO_FOR_PROJECT, this::noBaseAnalysisButValidateProjectUuidArgument); - - Component root = builder.build(project, PROJECT_KEY); - assertThat(root.getReportAttributes().getVersion()).isEqualTo(DEFAULT_VERSION); - } - - private Optional noBaseAnalysisButValidateProjectUuidArgument(String projectUuid) { - assertThat(projectUuid).isEqualTo(SIMPLE_UUID_GENERATOR.apply(PROJECT_KEY)); - return Optional.absent(); - } - - @Test - public void version_of_project_is_set_to_base_analysis_version_when_unset_in_Scanner_Component_and_base_analysis_has_a_version() { - ScannerReport.Component project = newBuilder().setType(PROJECT).build(); - - String expected = "some version"; - ComponentRootBuilder builder = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, - NO_COMPONENT_DTO_FOR_PROJECT, - (projectUuid) -> { - assertThat(projectUuid).isEqualTo(SIMPLE_UUID_GENERATOR.apply(PROJECT_KEY)); - return Optional.of(new SnapshotDto().setVersion(expected)); - }); - - Component root = builder.build(project, PROJECT_KEY); - assertThat(root.getReportAttributes().getVersion()).isEqualTo(expected); - } - - @Test - public void version_of_project_is_set_to_base_analysis_version_when_empty_in_Scanner_Component_and_base_analysis_has_a_version() { - ScannerReport.Component project = newBuilder().setType(PROJECT).setVersion("").build(); - - String expected = "some version"; - ComponentRootBuilder builder = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, NO_COMPONENT_DTO_FOR_PROJECT, - (projectUuid) -> { - assertThat(projectUuid).isEqualTo(SIMPLE_UUID_GENERATOR.apply(PROJECT_KEY)); - return Optional.of(new SnapshotDto().setVersion(expected)); - }); - - Component root = builder.build(project, PROJECT_KEY); - assertThat(root.getReportAttributes().getVersion()).isEqualTo(expected); - } - - @Test - public void version_of_project_is_set_to_default_value_when_unset_in_Scanner_Component_and_base_analysis_has_no_version() { - ScannerReport.Component project = newBuilder().setType(PROJECT).build(); - - ComponentRootBuilder builder = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, - NO_COMPONENT_DTO_FOR_PROJECT, - (projectUuid) -> { - assertThat(projectUuid).isEqualTo(SIMPLE_UUID_GENERATOR.apply(PROJECT_KEY)); - return Optional.of(new SnapshotDto()); - }); - - Component root = builder.build(project, PROJECT_KEY); - assertThat(root.getReportAttributes().getVersion()).isEqualTo(DEFAULT_VERSION); - } - - @Test - public void version_of_project_is_set_to_default_value_when_empty_in_Scanner_Component_and_base_analysis_has_no_version() { - ScannerReport.Component project = newBuilder().setType(PROJECT).setVersion("").build(); - - ComponentRootBuilder builder = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, NO_COMPONENT_DTO_FOR_PROJECT, - (projectUuid) -> { - assertThat(projectUuid).isEqualTo(SIMPLE_UUID_GENERATOR.apply(PROJECT_KEY)); - return Optional.of(new SnapshotDto()); - }); - - Component root = builder.build(project, PROJECT_KEY); - assertThat(root.getReportAttributes().getVersion()).isEqualTo(DEFAULT_VERSION); - } - - @Test - public void version_of_project_is_set_to_value_in_Scanner_Component_when_set() { - String expected = "some version"; - ScannerReport.Component project = newBuilder().setType(PROJECT).setVersion(expected).build(); - ComponentRootBuilder builder = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, NO_COMPONENT_DTO_FOR_PROJECT, - this::noBaseAnalysisButEnsureIsNotCalled); - - assertThat(builder.build(project, PROJECT_KEY).getReportAttributes().getVersion()).isEqualTo(expected); - } - - private Optional noBaseAnalysisButEnsureIsNotCalled(String projectUuid) { - fail("baseAnalysis provider should not have been called"); - return Optional.absent(); - } - - @Test - public void uuid_is_value_from_uuid_supplier_for_project_module_directory_and_file() { - ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(2).build(); - scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setKey(MODULE_KEY).addChildRef(3)); - scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setPath(DIRECTORY_PATH).addChildRef(4)); - scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setPath(FILE_PATH).setLines(1)); - - Component root = underTest.build(project, PROJECT_KEY); - Map componentByRef = indexComponentByRef(root); - assertThat(componentByRef.get(1).getUuid()).isEqualTo(SIMPLE_UUID_GENERATOR.apply(PROJECT_KEY)); - assertThat(componentByRef.get(2).getUuid()).isEqualTo(SIMPLE_UUID_GENERATOR.apply(MODULE_KEY)); - assertThat(componentByRef.get(3).getUuid()).isEqualTo(SIMPLE_UUID_GENERATOR.apply(DIRECTORY_KEY)); - assertThat(componentByRef.get(4).getUuid()).isEqualTo(SIMPLE_UUID_GENERATOR.apply(FILE_KEY)); - - } - - @Test - public void description_of_project_module_directory_and_file_is_null_when_unset_in_Scanner_Component() { - ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(2).build(); - scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).addChildRef(3)); - scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).addChildRef(4)); - scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setLines(1)); - - Component root = underTest.build(project, PROJECT_KEY); - Map componentByRef = indexComponentByRef(root); - assertThat(componentByRef.get(1).getDescription()).isNull(); - assertThat(componentByRef.get(2).getDescription()).isNull(); - assertThat(componentByRef.get(3).getDescription()).isNull(); - assertThat(componentByRef.get(4).getDescription()).isNull(); - } - - @Test - public void description_of_project_module_directory_and_file_is_null_when_empty_in_Scanner_Component() { - ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).setDescription("").addChildRef(2).build(); - scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setDescription("").addChildRef(3)); - scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setDescription("").addChildRef(4)); - scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setLines(1).setDescription("")); - - Component root = underTest.build(project, PROJECT_KEY); - Map componentByRef = indexComponentByRef(root); - assertThat(componentByRef.get(1).getDescription()).isNull(); - assertThat(componentByRef.get(2).getDescription()).isNull(); - assertThat(componentByRef.get(3).getDescription()).isNull(); - assertThat(componentByRef.get(4).getDescription()).isNull(); - } - - @Test - public void description_of_project_module_directory_and_file_is_description_of_Scanner_Component_when_set() { - ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).setDescription("desc of project").addChildRef(2).build(); - scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setDescription("desc of module").addChildRef(3)); - scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setDescription("desc of directory").addChildRef(4)); - scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setLines(1).setDescription("desc of file")); - - Component root = underTest.build(project, PROJECT_KEY); - Map componentByRef = indexComponentByRef(root); - assertThat(componentByRef.get(1).getDescription()).isEqualTo("desc of project"); - assertThat(componentByRef.get(2).getDescription()).isEqualTo("desc of module"); - assertThat(componentByRef.get(3).getDescription()).isEqualTo("desc of directory"); - assertThat(componentByRef.get(4).getDescription()).isEqualTo("desc of file"); - } - - @Test - public void all_types_but_UNSET_and_UNRECOGNIZED_are_converted() { - Arrays.stream(ScannerReport.Component.ComponentType.values()) - .filter((type) -> type != UNRECOGNIZED) - .filter((type) -> type != UNSET) - .forEach((type) -> assertThat(ComponentRootBuilder.convertType(type)).isEqualTo(Component.Type.valueOf(type.name()))); - } - - @Test - public void createOtherReportAttributes_takes_ref_version_and_path_from_Scanner_Component() { - int ref = 123; - String version = "1.0"; - String path = "some path"; - - ReportAttributes reportAttributes = createOtherReportAttributes(newBuilder() - .setRef(ref) - .setVersion(version) - .setPath(path) - .build()); - assertThat(reportAttributes.getRef()).isEqualTo(ref); - assertThat(reportAttributes.getPath()).isEqualTo(path); - assertThat(reportAttributes.getVersion()).isEqualTo(version); - } - - @Test - public void createOtherReportAttributes_sets_null_version_when_unset_in_Scanner_Component() { - ReportAttributes reportAttributes = createOtherReportAttributes(newBuilder().build()); - assertThat(reportAttributes.getVersion()).isNull(); - } - - @Test - public void createOtherReportAttributes_sets_null_version_when_empty_in_Scanner_Component() { - ReportAttributes reportAttributes = createOtherReportAttributes(newBuilder().setVersion("").build()); - assertThat(reportAttributes.getVersion()).isNull(); - } - - @Test - public void createOtherReportAttributes_sets_null_path_when_unset_in_Scanner_Component() { - ReportAttributes reportAttributes = createOtherReportAttributes(newBuilder().build()); - assertThat(reportAttributes.getPath()).isNull(); - } - - @Test - public void createOtherReportAttributes_sets_null_path_when_empty_in_Scanner_Component() { - ReportAttributes reportAttributes = createOtherReportAttributes(newBuilder().setPath("").build()); - assertThat(reportAttributes.getPath()).isNull(); - } - - @Test - public void createProjectReportAttributes_sets_null_path_when_unset_in_Scanner_Component() { - ReportAttributes reportAttributes = createProjectReportAttributes(newBuilder().build(), PROJECT_UUID, NO_BASEANALYSIS); - assertThat(reportAttributes.getPath()).isNull(); - } - - @Test - public void createProjectReportAttributes_sets_null_path_when_empty_in_Scanner_Component() { - ReportAttributes reportAttributes = createProjectReportAttributes(newBuilder().setPath("").build(), PROJECT_UUID, NO_BASEANALYSIS); - assertThat(reportAttributes.getPath()).isNull(); - } - - @Test - public void createFileAttributes_returns_null_when_type_is_not_FILE() { - Arrays.stream(ScannerReport.Component.ComponentType.values()) - .filter((type) -> type != UNRECOGNIZED) - .filter((type) -> type != FILE) - .map( - (type) -> newBuilder().setType(type).build()) - .forEach( - (component) -> assertThat(createFileAttributes(component)).isNull()); - } - - @Test - public void createFileAttributes_sets_language_to_null_when_unset_in_Scanner_Component() { - assertThat(createFileAttributes(newBuilder().setType(FILE).setLines(1).build()).getLanguageKey()).isNull(); - } - - @Test - public void createFileAttributes_sets_language_to_null_when_empty_in_Scanner_Component() { - assertThat(createFileAttributes(newBuilder().setType(FILE).setLanguage("").setLines(1).build()).getLanguageKey()).isNull(); - } - - @Test - public void createFileAttributes_sets_unitTest_from_Scanner_Component() { - assertThat(createFileAttributes(newBuilder().setType(FILE).setLines(1).build()).isUnitTest()).isFalse(); - assertThat(createFileAttributes(newBuilder().setType(FILE).setIsTest(true).setLines(1).build()).isUnitTest()).isTrue(); - } - - @Test - public void createFileAttributes_sets_lines_in_Scanner_Component() { - assertThat(createFileAttributes(newBuilder().setType(FILE).setLines(10).build()).getLines()).isEqualTo(10); - } - - @Test - public void fail_with_IAE_when_createFileAttributes_lines_is_not_set() throws Exception { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("File 'src/main/java/Main.java' has no line"); - createFileAttributes(newBuilder().setType(FILE).setPath("src/main/java/Main.java").build()); - } - - @Test - public void fail_with_IAE_when_createFileAttributes_sets_lines_to_0() throws Exception { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("File 'src/main/java/Main.java' has no line"); - createFileAttributes(newBuilder().setType(FILE).setPath("src/main/java/Main.java").setLines(0).build()); - } - - @Test - public void fail_with_IAE_when_createFileAttributes_sets_lines_to_less_than_0() throws Exception { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("File 'src/main/java/Main.java' has no line"); - createFileAttributes(newBuilder().setType(FILE).setPath("src/main/java/Main.java").setLines(-10).build()); - } - - private static class ScannerComponentProvider extends ExternalResource implements Function { - private final Map components = new HashMap<>(); - - @Override - protected void before() throws Throwable { - components.clear(); - } - - @Override - public ScannerReport.Component apply(Integer componentRef) { - return checkNotNull(components.get(componentRef), "No Component for componentRef %s", componentRef); - } - - public ScannerReport.Component add(ScannerReport.Component.Builder builder) { - ScannerReport.Component component = builder.build(); - ScannerReport.Component existing = components.put(component.getRef(), component); - checkArgument(existing == null, "Component %s already set for ref %s", existing, component.getRef()); - return component; - } - } - - private static Map indexComponentByRef(Component root) { - Map componentsByRef = new HashMap<>(); - new DepthTraversalTypeAwareCrawler( - new TypeAwareVisitorAdapter(CrawlerDepthLimit.FILE, PRE_ORDER) { - @Override - public void visitAny(Component any) { - componentsByRef.put(any.getReportAttributes().getRef(), any); - } - }).visit(root); - return componentsByRef; - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilderTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilderTest.java new file mode 100644 index 00000000000..6697a44b266 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilderTest.java @@ -0,0 +1,735 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.component; + +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import javax.annotation.Nullable; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.ExternalResource; +import org.sonar.core.component.ComponentKeys; +import org.sonar.db.component.SnapshotDto; +import org.sonar.scanner.protocol.output.ScannerReport; +import org.sonar.server.computation.task.projectanalysis.analysis.Project; + +import static com.google.common.base.Preconditions.checkArgument; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; +import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.DIRECTORY; +import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.FILE; +import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.MODULE; +import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.PROJECT; +import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.UNRECOGNIZED; +import static org.sonar.scanner.protocol.output.ScannerReport.Component.newBuilder; +import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER; + +public class ComponentTreeBuilderTest { + + private static final ComponentKeyGenerator KEY_GENERATOR = (module, component) -> "generated_" + + ComponentKeys.createEffectiveKey(module.getKey(), component != null ? component.getPath() : null); + private static final Function UUID_SUPPLIER = (componentKey) -> componentKey + "_uuid"; + private static final EnumSet REPORT_TYPES = EnumSet.of(PROJECT, MODULE, DIRECTORY, FILE); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Rule + public ScannerComponentProvider scannerComponentProvider = new ScannerComponentProvider(); + + private Project projectInDb = new Project(UUID_SUPPLIER.apply("K1"), "K1", "theProjectName"); + + @Test + public void build_throws_IAE_for_all_types_but_PROJECT_MODULE_DIRECTORY_FILE() { + Arrays.stream(ScannerReport.Component.ComponentType.values()) + .filter((type) -> type != UNRECOGNIZED) + .filter((type) -> !REPORT_TYPES.contains(type)) + .forEach( + (type) -> { + ScannerReport.Component component = newBuilder().setType(type).build(); + try { + call(component); + fail("Should have thrown a IllegalArgumentException"); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessage("Unsupported component type '" + type + "'"); + } + }); + } + + @Test + public void by_default_project_is_loaded_from_report() { + String nameInReport = "the name"; + String descriptionInReport = "the desc"; + Component root = call(newBuilder() + .setType(PROJECT) + .setKey(projectInDb.getKey()) + .setRef(42) + .setName(nameInReport) + .setDescription(descriptionInReport) + .setVersion("6.5") + .build()); + + assertThat(root.getUuid()).isEqualTo("generated_K1_uuid"); + assertThat(root.getKey()).isEqualTo("generated_K1"); + assertThat(root.getType()).isEqualTo(Component.Type.PROJECT); + assertThat(root.getName()).isEqualTo(nameInReport); + assertThat(root.getDescription()).isEqualTo(descriptionInReport); + assertThat(root.getReportAttributes().getRef()).isEqualTo(42); + assertThat(root.getReportAttributes().getPath()).isNull(); + assertThat(root.getReportAttributes().getVersion()).isEqualTo("6.5"); + assertThatFileAttributesAreNotSet(root); + } + + @Test + public void project_name_is_loaded_from_db_if_absent_from_report() { + Component root = call(newBuilder() + .setType(PROJECT) + .build()); + + assertThat(root.getName()).isEqualTo(projectInDb.getName()); + } + + @Test + public void project_version_is_loaded_from_db_if_absent_from_report() { + SnapshotDto baseAnalysis = new SnapshotDto().setVersion("6.5"); + Component root = call(newBuilder() + .setType(PROJECT) + .build(), baseAnalysis); + + assertThat(root.getReportAttributes().getVersion()).isEqualTo("6.5"); + } + + @Test + public void project_version_is_loaded_from_db_if_empty_report() { + SnapshotDto baseAnalysis = new SnapshotDto().setVersion("6.5"); + Component root = call(newBuilder() + .setType(PROJECT) + .setVersion("") + .build(), baseAnalysis); + + assertThat(root.getReportAttributes().getVersion()).isEqualTo("6.5"); + } + + @Test + public void project_version_is_hardcoded_if_absent_from_report_and_db() { + Component root = call(newBuilder() + .setType(PROJECT) + .build()); + + assertThat(root.getReportAttributes().getVersion()).isEqualTo("not provided"); + } + + @Test + public void project_description_is_null_if_absent_from_report() { + Component root = call(newBuilder() + .setType(PROJECT) + .build()); + + assertThat(root.getDescription()).isNull(); + } + + @Test + public void keys_of_module_directory_and_file_are_generated() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setKey(projectInDb.getKey()) + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(MODULE) + .setKey("M") + .addChildRef(3)); + scannerComponentProvider.add(newBuilder() + .setRef(3) + .setType(DIRECTORY) + .setPath("src/js") + .addChildRef(4)); + scannerComponentProvider.add(newBuilder() + .setRef(4) + .setType(FILE) + .setPath("src/js/Foo.js") + .setLines(1)); + + Component root = call(project); + assertThat(root.getKey()).isEqualTo("generated_" + projectInDb.getKey()); + assertThat(root.getChildren()).hasSize(1); + + Component module = root.getChildren().iterator().next(); + assertThat(module.getKey()).isEqualTo("generated_M"); + assertThat(module.getChildren()).hasSize(1); + + Component directory = module.getChildren().iterator().next(); + assertThat(directory.getKey()).isEqualTo("generated_M:src/js"); + assertThat(directory.getChildren()).hasSize(1); + + Component file = directory.getChildren().iterator().next(); + assertThat(file.getKey()).isEqualTo("generated_M:src/js/Foo.js"); + assertThat(file.getChildren()).isEmpty(); + } + + @Test + public void names_of_module_directory_and_file_are_keys_if_names_are_absent_from_report() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setKey(projectInDb.getKey()) + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(MODULE) + .setKey("M") + .addChildRef(3)); + scannerComponentProvider.add(newBuilder() + .setRef(3) + .setType(DIRECTORY) + .setPath("src/js") + .addChildRef(4)); + scannerComponentProvider.add(newBuilder() + .setRef(4) + .setType(FILE) + .setPath("src/js/Foo.js") + .setLines(1)); + + Component root = call(project); + + Component module = root.getChildren().iterator().next(); + assertThat(module.getName()).isEqualTo("generated_M"); + + Component directory = module.getChildren().iterator().next(); + assertThat(directory.getName()).isEqualTo("generated_M:src/js"); + + Component file = directory.getChildren().iterator().next(); + assertThat(file.getName()).isEqualTo("generated_M:src/js/Foo.js"); + } + + @Test + public void names_of_module_directory_and_file_are_keys_if_names_are_empty_in_report() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setKey(projectInDb.getKey()) + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(MODULE) + .setKey("M") + .setName("") + .addChildRef(3)); + scannerComponentProvider.add(newBuilder() + .setRef(3) + .setType(DIRECTORY) + .setPath("src/js") + .setName("") + .addChildRef(4)); + scannerComponentProvider.add(newBuilder() + .setRef(4) + .setType(FILE) + .setPath("src/js/Foo.js") + .setName("") + .setLines(1)); + + Component root = call(project); + + Component module = root.getChildren().iterator().next(); + assertThat(module.getName()).isEqualTo("generated_M"); + + Component directory = module.getChildren().iterator().next(); + assertThat(directory.getName()).isEqualTo("generated_M:src/js"); + + Component file = directory.getChildren().iterator().next(); + assertThat(file.getName()).isEqualTo("generated_M:src/js/Foo.js"); + } + + private void assertThatFileAttributesAreNotSet(Component root) { + try { + root.getFileAttributes(); + fail(); + } catch (IllegalStateException e) { + assertThat(e).hasMessage("Only component of type FILE have a FileAttributes object"); + } + } + + @Test + public void name_of_module_directory_and_files_includes_name_of_closest_module() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setKey("project 1") + .setRef(1) + .addChildRef(11).addChildRef(21).addChildRef(31).build(); + scannerComponentProvider.add(newBuilder().setRef(11).setType(MODULE).setKey("module 1").addChildRef(12).addChildRef(22).addChildRef(32)); + scannerComponentProvider.add(newBuilder().setRef(12).setType(MODULE).setKey("module 2").addChildRef(13).addChildRef(23).addChildRef(33)); + scannerComponentProvider.add(newBuilder().setRef(13).setType(MODULE).setKey("module 3").addChildRef(24).addChildRef(34)); + scannerComponentProvider.add(newBuilder().setRef(21).setType(DIRECTORY).setPath("directory in project").addChildRef(35)); + scannerComponentProvider.add(newBuilder().setRef(22).setType(DIRECTORY).setPath("directory in module 1").addChildRef(36)); + scannerComponentProvider.add(newBuilder().setRef(23).setType(DIRECTORY).setPath("directory in module 2").addChildRef(37)); + scannerComponentProvider.add(newBuilder().setRef(24).setType(DIRECTORY).setPath("directory in module 3").addChildRef(38)); + scannerComponentProvider.add(newBuilder().setRef(31).setType(FILE).setPath("file in project").setLines(1)); + scannerComponentProvider.add(newBuilder().setRef(32).setType(FILE).setPath("file in module 1").setLines(1)); + scannerComponentProvider.add(newBuilder().setRef(33).setType(FILE).setPath("file in module 2").setLines(1)); + scannerComponentProvider.add(newBuilder().setRef(34).setType(FILE).setPath("file in module 3").setLines(1)); + scannerComponentProvider.add(newBuilder().setRef(35).setType(FILE).setPath("file in directory in project").setLines(1)); + scannerComponentProvider.add(newBuilder().setRef(36).setType(FILE).setPath("file in directory in module 1").setLines(1)); + scannerComponentProvider.add(newBuilder().setRef(37).setType(FILE).setPath("file in directory in module 2").setLines(1)); + scannerComponentProvider.add(newBuilder().setRef(38).setType(FILE).setPath("file in directory in module 3").setLines(1)); + + Component root = call(project); + Map componentsByRef = indexComponentByRef(root); + assertThat(componentsByRef.get(11).getKey()).isEqualTo("generated_module 1"); + assertThat(componentsByRef.get(12).getKey()).isEqualTo("generated_module 2"); + assertThat(componentsByRef.get(13).getKey()).isEqualTo("generated_module 3"); + assertThat(componentsByRef.get(21).getKey()).startsWith("generated_project 1:"); + assertThat(componentsByRef.get(22).getKey()).startsWith("generated_module 1:"); + assertThat(componentsByRef.get(23).getKey()).startsWith("generated_module 2:"); + assertThat(componentsByRef.get(24).getKey()).startsWith("generated_module 3:"); + assertThat(componentsByRef.get(31).getKey()).startsWith("generated_project 1:"); + assertThat(componentsByRef.get(32).getKey()).startsWith("generated_module 1:"); + assertThat(componentsByRef.get(33).getKey()).startsWith("generated_module 2:"); + assertThat(componentsByRef.get(34).getKey()).startsWith("generated_module 3:"); + assertThat(componentsByRef.get(35).getKey()).startsWith("generated_project 1:"); + assertThat(componentsByRef.get(36).getKey()).startsWith("generated_module 1:"); + assertThat(componentsByRef.get(37).getKey()).startsWith("generated_module 2:"); + assertThat(componentsByRef.get(38).getKey()).startsWith("generated_module 3:"); + } + + @Test + public void uuids_are_provided_by_supplier() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setKey("c1") + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(MODULE) + .setKey("c2") + .addChildRef(3)); + scannerComponentProvider.add(newBuilder() + .setRef(3) + .setType(DIRECTORY) + .setPath("src/js") + .addChildRef(4)); + scannerComponentProvider.add(newBuilder() + .setRef(4) + .setType(FILE) + .setPath("src/js/Foo.js") + .setLines(1)); + + Component root = call(project); + assertThat(root.getUuid()).isEqualTo("generated_c1_uuid"); + + Component module = root.getChildren().iterator().next(); + assertThat(module.getUuid()).isEqualTo("generated_c2_uuid"); + + Component directory = module.getChildren().iterator().next(); + assertThat(directory.getUuid()).isEqualTo("generated_c2:src/js_uuid"); + + Component file = directory.getChildren().iterator().next(); + assertThat(file.getUuid()).isEqualTo("generated_c2:src/js/Foo.js_uuid"); + } + + @Test + public void descriptions_of_module_directory_and_file_are_null_if_absent_from_report() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(MODULE) + .addChildRef(3)); + scannerComponentProvider.add(newBuilder() + .setRef(3) + .setType(DIRECTORY) + .setPath("src/js") + .addChildRef(4)); + scannerComponentProvider.add(newBuilder() + .setRef(4) + .setType(FILE) + .setPath("src/js/Foo.js") + .setLines(1)); + + Component root = call(project); + + Component module = root.getChildren().iterator().next(); + assertThat(module.getDescription()).isNull(); + + Component directory = module.getChildren().iterator().next(); + assertThat(directory.getDescription()).isNull(); + + Component file = directory.getChildren().iterator().next(); + assertThat(file.getDescription()).isNull(); + } + + @Test + public void descriptions_of_module_directory_and_file_are_null_if_empty_in_report() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setRef(1) + .setDescription("") + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(MODULE) + .setDescription("") + .addChildRef(3)); + scannerComponentProvider.add(newBuilder() + .setRef(3) + .setType(DIRECTORY) + .setDescription("") + .setPath("src/js") + .addChildRef(4)); + scannerComponentProvider.add(newBuilder() + .setRef(4) + .setType(FILE) + .setDescription("") + .setPath("src/js/Foo.js") + .setLines(1)); + + Component root = call(project); + + Component module = root.getChildren().iterator().next(); + assertThat(module.getDescription()).isNull(); + + Component directory = module.getChildren().iterator().next(); + assertThat(directory.getDescription()).isNull(); + + Component file = directory.getChildren().iterator().next(); + assertThat(file.getDescription()).isNull(); + } + + @Test + public void descriptions_of_module_directory_and_file_are_set_from_report_if_present() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(MODULE) + .setDescription("b") + .addChildRef(3)); + scannerComponentProvider.add(newBuilder() + .setRef(3) + .setType(DIRECTORY) + .setDescription("c") + .setPath("src/js") + .addChildRef(4)); + scannerComponentProvider.add(newBuilder() + .setRef(4) + .setType(FILE) + .setDescription("d") + .setPath("src/js/Foo.js") + .setLines(1)); + + Component root = call(project); + + Component module = root.getChildren().iterator().next(); + assertThat(module.getDescription()).isEqualTo("b"); + + Component directory = module.getChildren().iterator().next(); + assertThat(directory.getDescription()).isEqualTo("c"); + + Component file = directory.getChildren().iterator().next(); + assertThat(file.getDescription()).isEqualTo("d"); + } + + @Test + public void versions_of_module_directory_and_file_are_set_from_report_if_present() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(MODULE) + .setVersion("v1") + .addChildRef(3)); + scannerComponentProvider.add(newBuilder() + .setRef(3) + .setType(DIRECTORY) + .setVersion("v2") + .setPath("src/js") + .addChildRef(4)); + scannerComponentProvider.add(newBuilder() + .setRef(4) + .setType(FILE) + .setVersion("v3") + .setPath("src/js/Foo.js") + .setLines(1)); + + Component root = call(project); + + Component module = root.getChildren().iterator().next(); + assertThat(module.getReportAttributes().getVersion()).isEqualTo("v1"); + + Component directory = module.getChildren().iterator().next(); + assertThat(directory.getReportAttributes().getVersion()).isEqualTo("v2"); + + Component file = directory.getChildren().iterator().next(); + assertThat(file.getReportAttributes().getVersion()).isEqualTo("v3"); + } + + @Test + public void versions_of_module_directory_and_file_are_null_if_absent_from_report() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(MODULE) + .addChildRef(3)); + scannerComponentProvider.add(newBuilder() + .setRef(3) + .setType(DIRECTORY) + .setPath("src/js") + .addChildRef(4)); + scannerComponentProvider.add(newBuilder() + .setRef(4) + .setType(FILE) + .setPath("src/js/Foo.js") + .setLines(1)); + + Component root = call(project); + + Component module = root.getChildren().iterator().next(); + assertThat(module.getReportAttributes().getVersion()).isNull(); + + Component directory = module.getChildren().iterator().next(); + assertThat(directory.getReportAttributes().getVersion()).isNull(); + + Component file = directory.getChildren().iterator().next(); + assertThat(file.getReportAttributes().getVersion()).isNull(); + } + + @Test + public void versions_of_module_directory_and_file_are_null_if_empty_in_report() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(MODULE) + .setVersion("") + .addChildRef(3)); + scannerComponentProvider.add(newBuilder() + .setRef(3) + .setType(DIRECTORY) + .setVersion("") + .setPath("src/js") + .addChildRef(4)); + scannerComponentProvider.add(newBuilder() + .setRef(4) + .setType(FILE) + .setVersion("") + .setPath("src/js/Foo.js") + .setLines(1)); + + Component root = call(project); + + Component module = root.getChildren().iterator().next(); + assertThat(module.getReportAttributes().getVersion()).isNull(); + + Component directory = module.getChildren().iterator().next(); + assertThat(directory.getReportAttributes().getVersion()).isNull(); + + Component file = directory.getChildren().iterator().next(); + assertThat(file.getReportAttributes().getVersion()).isNull(); + } + + @Test + public void only_nb_of_lines_is_mandatory_on_file_attributes() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(FILE) + .setPath("src/js/Foo.js") + .setLines(1)); + + Component root = call(project); + Component file = root.getChildren().iterator().next(); + assertThat(file.getFileAttributes().getLines()).isEqualTo(1); + assertThat(file.getFileAttributes().getLanguageKey()).isNull(); + assertThat(file.getFileAttributes().isUnitTest()).isFalse(); + } + + @Test + public void language_file_attributes_is_null_if_empty_in_report() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(FILE) + .setPath("src/js/Foo.js") + .setLines(1) + .setLanguage("")); + + Component root = call(project); + Component file = root.getChildren().iterator().next(); + assertThat(file.getFileAttributes().getLanguageKey()).isNull(); + } + + @Test + public void file_attributes_are_fully_loaded_from_report() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(FILE) + .setPath("src/js/Foo.js") + .setLines(1) + .setLanguage("js") + .setIsTest(true)); + + Component root = call(project); + Component file = root.getChildren().iterator().next(); + assertThat(file.getFileAttributes().getLines()).isEqualTo(1); + assertThat(file.getFileAttributes().getLanguageKey()).isEqualTo("js"); + assertThat(file.getFileAttributes().isUnitTest()).isTrue(); + } + + @Test + public void throw_IAE_if_lines_is_absent_from_report() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(FILE) + .setPath("src/js/Foo.js")); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("File 'src/js/Foo.js' has no line"); + + call(project); + } + + @Test + public void throw_IAE_if_lines_is_zero_in_report() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(FILE) + .setPath("src/js/Foo.js") + .setLines(0)); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("File 'src/js/Foo.js' has no line"); + + call(project); + } + + @Test + public void throw_IAE_if_lines_is_negative_in_report() { + ScannerReport.Component project = newBuilder() + .setType(PROJECT) + .setRef(1) + .addChildRef(2) + .build(); + scannerComponentProvider.add(newBuilder() + .setRef(2) + .setType(FILE) + .setPath("src/js/Foo.js") + .setLines(-10)); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("File 'src/js/Foo.js' has no line"); + + call(project); + } + + private static class ScannerComponentProvider extends ExternalResource implements Function { + private final Map components = new HashMap<>(); + + @Override + protected void before() throws Throwable { + components.clear(); + } + + @Override + public ScannerReport.Component apply(Integer componentRef) { + return Objects.requireNonNull(components.get(componentRef), "No Component for componentRef " + componentRef); + } + + public ScannerReport.Component add(ScannerReport.Component.Builder builder) { + ScannerReport.Component component = builder.build(); + ScannerReport.Component existing = components.put(component.getRef(), component); + checkArgument(existing == null, "Component %s already set for ref %s", existing, component.getRef()); + return component; + } + } + + private Component call(ScannerReport.Component project) { + return newUnderTest(null).buildProject(project); + } + + private Component call(ScannerReport.Component project, @Nullable SnapshotDto baseAnalysis) { + return newUnderTest(baseAnalysis).buildProject(project); + } + + private ComponentTreeBuilder newUnderTest(@Nullable SnapshotDto baseAnalysis) { + return new ComponentTreeBuilder(KEY_GENERATOR, UUID_SUPPLIER, scannerComponentProvider, projectInDb, baseAnalysis); + } + + private static Map indexComponentByRef(Component root) { + Map componentsByRef = new HashMap<>(); + new DepthTraversalTypeAwareCrawler( + new TypeAwareVisitorAdapter(CrawlerDepthLimit.FILE, PRE_ORDER) { + @Override + public void visitAny(Component any) { + componentsByRef.put(any.getReportAttributes().getRef(), any); + } + }).visit(root); + return componentsByRef; + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentUuidFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentUuidFactoryTest.java new file mode 100644 index 00000000000..22c879837a3 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentUuidFactoryTest.java @@ -0,0 +1,57 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.component; + +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.utils.System2; +import org.sonar.db.DbTester; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ComponentTesting; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ComponentUuidFactoryTest { + + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + @Test + public void load_uuids_from_existing_components_in_db() { + ComponentDto project = db.components().insertPrivateProject(); + ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project)); + + ComponentUuidFactory underTest = new ComponentUuidFactory(db.getDbClient(), db.getSession(), project.getDbKey()); + assertThat(underTest.getOrCreateForKey(project.getDbKey())).isEqualTo(project.uuid()); + assertThat(underTest.getOrCreateForKey(module.getDbKey())).isEqualTo(module.uuid()); + } + + @Test + public void generate_uuid_if_it_does_not_exist_in_db() { + ComponentUuidFactory underTest = new ComponentUuidFactory(db.getDbClient(), db.getSession(), "theProjectKey"); + + String generatedKey = underTest.getOrCreateForKey("foo"); + assertThat(generatedKey).isNotEmpty(); + + // uuid is kept in memory for further calls with same key + assertThat(underTest.getOrCreateForKey("foo")).isEqualTo(generatedKey); + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ConfigurationRepositoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ConfigurationRepositoryTest.java index 383de8d5030..26fe4fddfdc 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ConfigurationRepositoryTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ConfigurationRepositoryTest.java @@ -19,19 +19,17 @@ */ package org.sonar.server.computation.task.projectanalysis.component; -import org.junit.After; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.sonar.api.config.Configuration; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.utils.System2; +import org.sonar.ce.queue.CeTask; import org.sonar.ce.settings.ProjectConfigurationFactory; import org.sonar.db.DbClient; -import org.sonar.db.DbSession; import org.sonar.db.DbTester; +import org.sonar.db.ce.CeTaskTypes; import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ComponentTesting; import org.sonar.db.property.PropertyDto; import static org.assertj.core.api.Assertions.assertThat; @@ -40,47 +38,36 @@ import static org.sonar.server.computation.task.projectanalysis.component.Compon public class ConfigurationRepositoryTest { private static final Component ROOT = ReportComponent.builder(PROJECT, 1).setKey("ROOT").build(); + private static final CeTask TASK = new CeTask.Builder() + .setOrganizationUuid("foo") + .setUuid("bar") + .setType(CeTaskTypes.REPORT) + .setComponentUuid(ROOT.getUuid()) + .setComponentKey(ROOT.getKey()) + .build(); @Rule - public final DbTester dbTester = DbTester.create(System2.INSTANCE); + public final DbTester db = DbTester.create(System2.INSTANCE); - DbClient dbClient = dbTester.getDbClient(); - - DbSession session; - - MapSettings globalSettings; - - ConfigurationRepository underTest; - - @Before - public void createDao() { - globalSettings = new MapSettings(); - session = dbClient.openSession(false); - underTest = new ConfigurationRepositoryImpl(new ProjectConfigurationFactory(globalSettings, dbClient)); - } - - @After - public void tearDown() { - session.close(); - } + private DbClient dbClient = db.getDbClient(); + private MapSettings globalSettings = new MapSettings(); + private ConfigurationRepository underTest = new ConfigurationRepositoryImpl(TASK, new ProjectConfigurationFactory(globalSettings, dbClient)); @Test public void get_project_settings_from_global_settings() { globalSettings.setProperty("key", "value"); - Configuration config = underTest.getConfiguration(ROOT); + Configuration config = underTest.getConfiguration(); assertThat(config.get("key")).hasValue("value"); } @Test public void get_project_settings_from_db() { - ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert()).setDbKey(ROOT.getKey()); - dbClient.componentDao().insert(session, project); - dbClient.propertiesDao().saveProperty(session, new PropertyDto().setResourceId(project.getId()).setKey("key").setValue("value")); - session.commit(); + ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey(ROOT.getKey())); + insertProjectProperty(project, "key", "value"); - Configuration config = underTest.getConfiguration(ROOT); + Configuration config = underTest.getConfiguration(); assertThat(config.get("key")).hasValue("value"); } @@ -89,10 +76,38 @@ public class ConfigurationRepositoryTest { public void call_twice_get_project_settings() { globalSettings.setProperty("key", "value"); - Configuration config = underTest.getConfiguration(ROOT); + Configuration config = underTest.getConfiguration(); assertThat(config.get("key")).hasValue("value"); - config = underTest.getConfiguration(ROOT); + config = underTest.getConfiguration(); assertThat(config.get("key")).hasValue("value"); } + + @Test + public void project_settings_override_global_settings() { + globalSettings.setProperty("key", "value1"); + ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey(ROOT.getKey())); + insertProjectProperty(project, "key", "value2"); + + Configuration config = underTest.getConfiguration(); + assertThat(config.get("key")).hasValue("value2"); + } + + @Test + public void project_settings_are_cached_to_avoid_db_access() { + ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey(ROOT.getKey())); + insertProjectProperty(project, "key", "value"); + + Configuration config = underTest.getConfiguration(); + assertThat(config.get("key")).hasValue("value"); + + db.executeUpdateSql("delete from properties"); + db.commit(); + + assertThat(config.get("key")).hasValue("value"); + } + + private void insertProjectProperty(ComponentDto project, String propertyKey, String propertyValue) { + db.properties().insertProperties(new PropertyDto().setKey(propertyKey).setValue(propertyValue).setResourceId(project.getId())); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/MainBranchImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/MainBranchImplTest.java new file mode 100644 index 00000000000..a14e07a4741 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/MainBranchImplTest.java @@ -0,0 +1,92 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.component; + +import javax.annotation.Nullable; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.MessageException; +import org.sonar.db.component.BranchType; +import org.sonar.scanner.protocol.output.ScannerReport; +import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType; + +import static org.assertj.core.api.Assertions.assertThat; + +public class MainBranchImplTest { + + private static final ScannerReport.Component PROJECT = ScannerReport.Component.newBuilder().setType(ComponentType.PROJECT).setKey("P").build(); + private static final ScannerReport.Component MODULE = ScannerReport.Component.newBuilder().setType(ComponentType.MODULE).setKey("M").build(); + private static final ScannerReport.Component FILE = ScannerReport.Component.newBuilder().setType(ComponentType.FILE).setPath("src/Foo.js").build(); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void throw_ME_if_name_contains_invalid_characters() { + assertThatNameIsCorrect("master"); + assertThatNameIsCorrect("feature/foo"); + assertThatNameIsCorrect("feature_foo"); + + assertThatNameIsNotCorrect("feature foo"); + assertThatNameIsNotCorrect("feature#foo"); + } + + @Test + public void default_branch_represents_the_project() { + MainBranchImpl branch = new MainBranchImpl(null); + + assertThat(branch.isMain()).isTrue(); + assertThat(branch.getType()).isEqualTo(BranchType.LONG); + assertThat(branch.getName()).isEmpty(); + assertThat(branch.supportsCrossProjectCpd()).isTrue(); + + assertThat(branch.generateKey(PROJECT, null)).isEqualTo("P"); + assertThat(branch.generateKey(MODULE, null)).isEqualTo("M"); + assertThat(branch.generateKey(MODULE, FILE)).isEqualTo("M:src/Foo.js"); + } + + @Test + public void branch_represents_a_forked_project_with_different_key() { + MainBranchImpl branch = new MainBranchImpl("bar"); + + // not a real branch. Parameter sonar.branch forks project. + assertThat(branch.isMain()).isTrue(); + assertThat(branch.getType()).isEqualTo(BranchType.LONG); + assertThat(branch.getName()).hasValue("bar"); + assertThat(branch.supportsCrossProjectCpd()).isFalse(); + + assertThat(branch.generateKey(PROJECT, null)).isEqualTo("P:bar"); + assertThat(branch.generateKey(MODULE, null)).isEqualTo("M:bar"); + assertThat(branch.generateKey(MODULE, FILE)).isEqualTo("M:bar:src/Foo.js"); + } + + private void assertThatNameIsCorrect(@Nullable String name) { + MainBranchImpl branch = new MainBranchImpl(name); + assertThat(branch.getName()).hasValue(name); + } + + private void assertThatNameIsNotCorrect(String name) { + expectedException.expect(MessageException.class); + expectedException.expectMessage("\"" + name + "\" is not a valid branch name. Allowed characters are alphanumeric, '-', '_', '.' and '/'."); + + new MainBranchImpl(name); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/TestSettingsRepository.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/TestSettingsRepository.java index b436f0d38d2..8f453755ac5 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/TestSettingsRepository.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/TestSettingsRepository.java @@ -34,7 +34,7 @@ public class TestSettingsRepository implements ConfigurationRepository { } @Override - public Configuration getConfiguration(Component component) { + public Configuration getConfiguration() { return config; } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/duplication/CrossProjectDuplicationStatusHolderImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/duplication/CrossProjectDuplicationStatusHolderImplTest.java index c03d9d74ca1..2fb55e83646 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/duplication/CrossProjectDuplicationStatusHolderImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/duplication/CrossProjectDuplicationStatusHolderImplTest.java @@ -25,13 +25,14 @@ import org.junit.rules.ExpectedException; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; +import org.sonar.server.computation.task.projectanalysis.analysis.Branch; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class CrossProjectDuplicationStatusHolderImplTest { - private static String BRANCH = "origin/master"; - @Rule public ExpectedException thrown = ExpectedException.none(); @Rule @@ -45,7 +46,7 @@ public class CrossProjectDuplicationStatusHolderImplTest { public void cross_project_duplication_is_enabled_when_enabled_in_report_and_no_branch() throws Exception { analysisMetadataHolder .setCrossProjectDuplicationEnabled(true) - .setBranch(null); + .setBranch(newBranch(true)); underTest.start(); assertThat(underTest.isEnabled()).isTrue(); @@ -56,7 +57,7 @@ public class CrossProjectDuplicationStatusHolderImplTest { public void cross_project_duplication_is_disabled_when_not_enabled_in_report() throws Exception { analysisMetadataHolder .setCrossProjectDuplicationEnabled(false) - .setBranch(null); + .setBranch(newBranch(true)); underTest.start(); assertThat(underTest.isEnabled()).isFalse(); @@ -67,7 +68,7 @@ public class CrossProjectDuplicationStatusHolderImplTest { public void cross_project_duplication_is_disabled_when_branch_is_used() throws Exception { analysisMetadataHolder .setCrossProjectDuplicationEnabled(true) - .setBranch(BRANCH); + .setBranch(newBranch(false)); underTest.start(); assertThat(underTest.isEnabled()).isFalse(); @@ -78,7 +79,7 @@ public class CrossProjectDuplicationStatusHolderImplTest { public void cross_project_duplication_is_disabled_when_not_enabled_in_report_and_when_branch_is_used() throws Exception { analysisMetadataHolder .setCrossProjectDuplicationEnabled(false) - .setBranch(BRANCH); + .setBranch(newBranch(false)); underTest.start(); assertThat(underTest.isEnabled()).isFalse(); @@ -89,7 +90,7 @@ public class CrossProjectDuplicationStatusHolderImplTest { public void flag_is_build_in_start() throws Exception { analysisMetadataHolder .setCrossProjectDuplicationEnabled(true) - .setBranch(null); + .setBranch(newBranch(true)); underTest.start(); assertThat(underTest.isEnabled()).isTrue(); @@ -105,4 +106,10 @@ public class CrossProjectDuplicationStatusHolderImplTest { underTest.isEnabled(); } + + private static Branch newBranch(boolean supportsCrossProjectCpd) { + Branch branch = mock(Branch.class); + when(branch.supportsCrossProjectCpd()).thenReturn(supportsCrossProjectCpd); + return branch; + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/DefaultAssigneeTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/DefaultAssigneeTest.java index b65ecc8a1cb..aa29f66174e 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/DefaultAssigneeTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/DefaultAssigneeTest.java @@ -31,10 +31,8 @@ import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetada import org.sonar.server.computation.task.projectanalysis.analysis.Organization; import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; import org.sonar.server.computation.task.projectanalysis.component.TestSettingsRepository; -import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule; import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.server.computation.task.projectanalysis.component.ReportComponent.DUMB_PROJECT; public class DefaultAssigneeTest { @@ -44,15 +42,12 @@ public class DefaultAssigneeTest { @Rule public DbTester db = DbTester.create(); - @Rule - public TreeRootHolderRule rootHolder = new TreeRootHolderRule().setRoot(DUMB_PROJECT); - private MapSettings settings = new MapSettings(); private ConfigurationRepository settingsRepository = new TestSettingsRepository(settings.asConfig()); private AnalysisMetadataHolderImpl analysisMetadataHolder = new AnalysisMetadataHolderImpl(); private OrganizationDto organizationDto; - private DefaultAssignee underTest = new DefaultAssignee(db.getDbClient(), rootHolder, settingsRepository, analysisMetadataHolder); + private DefaultAssignee underTest = new DefaultAssignee(db.getDbClient(), settingsRepository, analysisMetadataHolder); @Before public void setUp() throws Exception { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/filter/IssueFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/filter/IssueFilterTest.java index 0c36fc90d9a..cca2eb90d92 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/filter/IssueFilterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/filter/IssueFilterTest.java @@ -80,7 +80,7 @@ public class IssueFilterTest { @Test public void ignore_all() throws Exception { - IssueFilter underTest = newIssueFilter(newSettings(asList("*", "**"), Collections.emptyList())); + IssueFilter underTest = newIssueFilter(newSettings(asList("*", "**"), Collections.emptyList())); assertThat(underTest.accept(ISSUE_1, COMPONENT_1)).isFalse(); assertThat(underTest.accept(ISSUE_2, COMPONENT_1)).isFalse(); @@ -89,7 +89,7 @@ public class IssueFilterTest { @Test public void ignore_some_rule_and_component() throws Exception { - IssueFilter underTest = newIssueFilter(newSettings(asList("xoo:x1", "**/xoo/File1*"), Collections.emptyList())); + IssueFilter underTest = newIssueFilter(newSettings(asList("xoo:x1", "**/xoo/File1*"), Collections.emptyList())); assertThat(underTest.accept(ISSUE_1, COMPONENT_1)).isFalse(); assertThat(underTest.accept(ISSUE_1, COMPONENT_2)).isTrue(); @@ -101,7 +101,7 @@ public class IssueFilterTest { public void ignore_many_rules() throws Exception { IssueFilter underTest = newIssueFilter(newSettings( asList("xoo:x1", "**/xoo/File1*", "xoo:x2", "**/xoo/File1*"), - Collections.emptyList())); + Collections.emptyList())); assertThat(underTest.accept(ISSUE_1, COMPONENT_1)).isFalse(); assertThat(underTest.accept(ISSUE_1, COMPONENT_2)).isTrue(); @@ -111,7 +111,7 @@ public class IssueFilterTest { @Test public void include_all() throws Exception { - IssueFilter underTest = newIssueFilter(newSettings(Collections.emptyList(), asList("*", "**"))); + IssueFilter underTest = newIssueFilter(newSettings(Collections.emptyList(), asList("*", "**"))); assertThat(underTest.accept(ISSUE_1, COMPONENT_1)).isTrue(); assertThat(underTest.accept(ISSUE_2, COMPONENT_1)).isTrue(); @@ -120,7 +120,7 @@ public class IssueFilterTest { @Test public void include_some_rule_and_component() throws Exception { - IssueFilter underTest = newIssueFilter(newSettings(Collections.emptyList(), asList("xoo:x1", "**/xoo/File1*"))); + IssueFilter underTest = newIssueFilter(newSettings(Collections.emptyList(), asList("xoo:x1", "**/xoo/File1*"))); assertThat(underTest.accept(ISSUE_1, COMPONENT_1)).isTrue(); assertThat(underTest.accept(ISSUE_1, COMPONENT_2)).isFalse(); @@ -145,7 +145,7 @@ public class IssueFilterTest { @Test public void include_many_rules() throws Exception { IssueFilter underTest = newIssueFilter(newSettings( - Collections.emptyList(), + Collections.emptyList(), asList("xoo:x1", "**/xoo/File1*", "xoo:x2", "**/xoo/File1*"))); assertThat(underTest.accept(ISSUE_1, COMPONENT_1)).isTrue(); @@ -169,7 +169,7 @@ public class IssueFilterTest { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("File path pattern cannot be empty. Please check 'sonar.issue.ignore.multicriteria' settings"); - newIssueFilter(newSettings(asList("xoo:x1", ""), Collections.emptyList())); + newIssueFilter(newSettings(asList("xoo:x1", ""), Collections.emptyList())); } @Test @@ -177,12 +177,12 @@ public class IssueFilterTest { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Rule key pattern cannot be empty. Please check 'sonar.issue.enforce.multicriteria' settings"); - newIssueFilter(newSettings(Collections.emptyList(), asList("", "**"))); + newIssueFilter(newSettings(Collections.emptyList(), asList("", "**"))); } private IssueFilter newIssueFilter(MapSettings settings) { - when(settingsRepository.getConfiguration(PROJECT)).thenReturn(settings.asConfig()); - return new IssueFilter(treeRootHolder, settingsRepository); + when(settingsRepository.getConfiguration()).thenReturn(settings.asConfig()); + return new IssueFilter(settingsRepository); } private static MapSettings newSettings(List exclusionsProperties, List inclusionsProperties) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStepTest.java index b949295806c..072d0ae3170 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStepTest.java @@ -37,9 +37,8 @@ import org.sonar.db.organization.OrganizationDto; import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType; import org.sonar.scanner.protocol.output.ScannerReport.Component.FileStatus; -import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderImpl; -import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolder; import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolderRule; +import org.sonar.server.computation.task.projectanalysis.analysis.Project; import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderRule; import org.sonar.server.computation.task.projectanalysis.component.Component; import org.sonar.server.computation.task.projectanalysis.component.MutableTreeRootHolderRule; @@ -91,7 +90,8 @@ public class BuildComponentTreeStepTest { public MutableAnalysisMetadataHolderRule analysisMetadataHolder = new MutableAnalysisMetadataHolderRule() .setRootComponentRef(ROOT_REF) .setAnalysisDate(ANALYSIS_DATE) - .setBranch(null); + .setBranch(null) + .setProject(new Project("U1", REPORT_PROJECT_KEY, REPORT_PROJECT_KEY)); private DbClient dbClient = dbTester.getDbClient(); private BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder); @@ -190,27 +190,27 @@ public class BuildComponentTreeStepTest { verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":" + REPORT_FILE_KEY_1, "DEFG"); } - @Test - public void use_branch_to_generate_keys() { - MutableAnalysisMetadataHolder analysisMetadataHolder = new AnalysisMetadataHolderImpl() - .setRootComponentRef(ROOT_REF) - .setAnalysisDate(ANALYSIS_DATE) - .setBranch("origin/master"); - - BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder); - - reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF)); - reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1)); - reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF)); - reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1)); - - underTest.execute(); - - verifyComponent(ROOT_REF, REPORT_PROJECT_KEY + ":origin/master"); - verifyComponent(MODULE_REF, REPORT_MODULE_KEY + ":origin/master"); - verifyComponent(DIR_REF_1, REPORT_MODULE_KEY + ":origin/master:" + REPORT_DIR_KEY_1); - verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":origin/master:" + REPORT_FILE_KEY_1); - } +// @Test +// public void use_branch_to_generate_keys() { +// MutableAnalysisMetadataHolder analysisMetadataHolder = new AnalysisMetadataHolderImpl() +// .setRootComponentRef(ROOT_REF) +// .setAnalysisDate(ANALYSIS_DATE) +// .setBranch("origin/master"); +// +// BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder); +// +// reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF)); +// reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1)); +// reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF)); +// reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1)); +// +// underTest.execute(); +// +// verifyComponent(ROOT_REF, REPORT_PROJECT_KEY + ":origin/master"); +// verifyComponent(MODULE_REF, REPORT_MODULE_KEY + ":origin/master"); +// verifyComponent(DIR_REF_1, REPORT_MODULE_KEY + ":origin/master:" + REPORT_DIR_KEY_1); +// verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":origin/master:" + REPORT_FILE_KEY_1); +// } @Test public void compute_keys_and_uuids_on_project_having_module_and_directory() { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadPeriodsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadPeriodsStepTest.java index c852a367335..8d45b82f8a7 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadPeriodsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadPeriodsStepTest.java @@ -86,7 +86,7 @@ public class LoadPeriodsStepTest extends BaseStepTest { private void setupRoot(Component root) { treeRootHolder.setRoot(root); - when(settingsRepository.getConfiguration(root)).thenReturn(settings.asConfig()); + when(settingsRepository.getConfiguration()).thenReturn(settings.asConfig()); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateLoadingStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadQualityGateStepTest.java similarity index 60% rename from server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateLoadingStepTest.java rename to server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadQualityGateStepTest.java index 7e671ffe00e..0cce63f085d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/QualityGateLoadingStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadQualityGateStepTest.java @@ -25,12 +25,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.config.internal.MapSettings; -import org.sonar.server.computation.task.projectanalysis.component.Component; import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; -import org.sonar.server.computation.task.projectanalysis.component.ReportComponent; -import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule; -import org.sonar.server.computation.task.projectanalysis.component.VisitException; -import org.sonar.server.computation.task.projectanalysis.qualitygate.Condition; import org.sonar.server.computation.task.projectanalysis.qualitygate.MutableQualityGateHolderRule; import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGate; import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGateService; @@ -42,57 +37,46 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -import static org.sonar.test.ExceptionCauseMatcher.hasType; -public class QualityGateLoadingStepTest { - private static final String PROJECT_KEY = "project key"; - private static final ReportComponent PROJECT_ALONE = ReportComponent.builder(Component.Type.PROJECT, 1).setKey(PROJECT_KEY).build(); +public class LoadQualityGateStepTest { @Rule public ExpectedException expectedException = ExpectedException.none(); @Rule - public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); - @Rule public MutableQualityGateHolderRule mutableQualityGateHolder = new MutableQualityGateHolderRule(); private ConfigurationRepository settingsRepository = mock(ConfigurationRepository.class); private QualityGateService qualityGateService = mock(QualityGateService.class); - private LoadQualityGateStep underTest = new LoadQualityGateStep(treeRootHolder, settingsRepository, qualityGateService, mutableQualityGateHolder); + private LoadQualityGateStep underTest = new LoadQualityGateStep(settingsRepository, qualityGateService, mutableQualityGateHolder); @Test public void execute_sets_default_QualityGate_when_project_has_no_settings() { - ReportComponent root = ReportComponent.builder(Component.Type.PROJECT, 1).setKey(PROJECT_KEY).addChildren(ReportComponent.builder(Component.Type.FILE, 2).build()).build(); - treeRootHolder.setRoot(root); - when(settingsRepository.getConfiguration(root)).thenReturn(new MapSettings().asConfig()); + when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().asConfig()); underTest.execute(); verifyNoQualityGate(); // verify only project is processed - verify(settingsRepository).getConfiguration(root); + verify(settingsRepository).getConfiguration(); verifyNoMoreInteractions(settingsRepository); } @Test public void execute_sets_default_QualityGate_when_property_value_is_not_a_long() { - expectedException.expect(VisitException.class); - expectedException.expectCause( - hasType(IllegalStateException.class) - .andMessage(format("Unsupported value (%s) in property sonar.qualitygate", "10 sds"))); + expectedException.expect(IllegalStateException.class); + expectedException.expectMessage(format("Unsupported value (%s) in property sonar.qualitygate", "10 sds")); - treeRootHolder.setRoot(PROJECT_ALONE); - when(settingsRepository.getConfiguration(PROJECT_ALONE)).thenReturn(new MapSettings().setProperty("sonar.qualitygate", "10 sds").asConfig()); + when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().setProperty("sonar.qualitygate", "10 sds").asConfig()); underTest.execute(); } @Test public void execute_sets_default_QualityGate_if_it_can_not_be_found_by_service() { - treeRootHolder.setRoot(PROJECT_ALONE); - when(settingsRepository.getConfiguration(PROJECT_ALONE)).thenReturn(new MapSettings().setProperty("sonar.qualitygate", 10).asConfig()); - when(qualityGateService.findById(10)).thenReturn(Optional.absent()); + when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().setProperty("sonar.qualitygate", 10).asConfig()); + when(qualityGateService.findById(10)).thenReturn(Optional.absent()); underTest.execute(); @@ -101,10 +85,9 @@ public class QualityGateLoadingStepTest { @Test public void execute_sets_QualityGate_if_it_can_be_found_by_service() { - QualityGate qualityGate = new QualityGate(465, "name", Collections.emptyList()); + QualityGate qualityGate = new QualityGate(465, "name", Collections.emptyList()); - treeRootHolder.setRoot(PROJECT_ALONE); - when(settingsRepository.getConfiguration(PROJECT_ALONE)).thenReturn(new MapSettings().setProperty("sonar.qualitygate", 10).asConfig()); + when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().setProperty("sonar.qualitygate", 10).asConfig()); when(qualityGateService.findById(10)).thenReturn(Optional.of(qualityGate)); underTest.execute(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStepTest.java index 2b1798b11a6..49b273283a8 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStepTest.java @@ -23,7 +23,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.mockito.ArgumentCaptor; import org.sonar.api.utils.MessageException; import org.sonar.api.utils.System2; import org.sonar.ce.queue.CeTask; @@ -31,35 +30,30 @@ import org.sonar.core.platform.PluginInfo; import org.sonar.core.platform.PluginRepository; import org.sonar.db.DbClient; import org.sonar.db.DbTester; +import org.sonar.db.component.ComponentDto; import org.sonar.db.organization.OrganizationDto; import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolderRule; import org.sonar.server.computation.task.projectanalysis.analysis.Organization; import org.sonar.server.computation.task.projectanalysis.analysis.ScannerPlugin; import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderRule; +import org.sonar.server.computation.task.projectanalysis.component.BranchLoader; import org.sonar.server.computation.task.step.ComputationStep; -import org.sonar.server.organization.BillingValidations; -import org.sonar.server.organization.BillingValidations.BillingValidationsException; -import org.sonar.server.organization.BillingValidationsProxy; import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.organization.TestDefaultOrganizationProvider; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class LoadReportAnalysisMetadataHolderStepTest { private static final String PROJECT_KEY = "project_key"; - private static final String BRANCH = "origin/master"; private static final long ANALYSIS_DATE = 123456789L; @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); + public DbTester db = DbTester.create(System2.INSTANCE); @Rule public BatchReportReaderRule reportReader = new BatchReportReaderRule(); @Rule @@ -67,16 +61,16 @@ public class LoadReportAnalysisMetadataHolderStepTest { @Rule public ExpectedException expectedException = ExpectedException.none(); - private DbClient dbClient = dbTester.getDbClient(); - private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester); - private BillingValidationsProxy billingValidations = mock(BillingValidationsProxy.class); + private DbClient dbClient = db.getDbClient(); + private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); private PluginRepository pluginRepository = mock(PluginRepository.class); private ComputationStep underTest; @Before public void setUp() { - CeTask defaultOrgCeTask = createCeTask(PROJECT_KEY, dbTester.getDefaultOrganization().getUuid()); + CeTask defaultOrgCeTask = createCeTask(PROJECT_KEY, db.getDefaultOrganization().getUuid()); underTest = createStep(defaultOrgCeTask); + db.components().insertPublicProject(db.getDefaultOrganization(), p -> p.setDbKey(PROJECT_KEY)); } @Test @@ -103,32 +97,6 @@ public class LoadReportAnalysisMetadataHolderStepTest { assertThat(analysisMetadataHolder.getAnalysisDate()).isEqualTo(ANALYSIS_DATE); } - @Test - public void set_branch() { - reportReader.setMetadata( - newBatchReportBuilder() - .setBranch(BRANCH) - .build()); - - CeTask ceTask = createCeTask(PROJECT_KEY + ":" + BRANCH, dbTester.getDefaultOrganization().getUuid()); - ComputationStep underTest = createStep(ceTask); - - underTest.execute(); - - assertThat(analysisMetadataHolder.getBranch()).isEqualTo(BRANCH); - } - - @Test - public void set_null_branch_when_nothing_in_the_report() { - reportReader.setMetadata( - newBatchReportBuilder() - .build()); - - underTest.execute(); - - assertThat(analysisMetadataHolder.getBranch()).isNull(); - } - @Test public void set_cross_project_duplication_to_true() { reportReader.setMetadata( @@ -192,6 +160,7 @@ public class LoadReportAnalysisMetadataHolderStepTest { public void execute_fails_with_MessageException_if_projectKey_is_null_in_CE_task() { CeTask res = mock(CeTask.class); when(res.getComponentUuid()).thenReturn("prj_uuid"); + when(res.getOrganizationUuid()).thenReturn(defaultOrganizationProvider.get().getUuid()); reportReader.setMetadata(ScannerReport.Metadata.newBuilder().build()); ComputationStep underTest = createStep(res); @@ -235,13 +204,13 @@ public class LoadReportAnalysisMetadataHolderStepTest { reportReader.setMetadata( newBatchReportBuilder() .build()); - OrganizationDto nonDefaultOrganizationDto = dbTester.organizations().insert(); + OrganizationDto nonDefaultOrganizationDto = db.organizations().insert(); ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, nonDefaultOrganizationDto.getUuid())); expectedException.expect(MessageException.class); expectedException.expectMessage("Report does not specify an OrganizationKey but it has been submitted to another organization (" + - nonDefaultOrganizationDto.getKey() + ") than the default one (" + dbTester.getDefaultOrganization().getKey() + ")"); + nonDefaultOrganizationDto.getKey() + ") than the default one (" + db.getDefaultOrganization().getKey() + ")"); underTest.execute(); } @@ -255,7 +224,7 @@ public class LoadReportAnalysisMetadataHolderStepTest { underTest.execute(); Organization organization = analysisMetadataHolder.getOrganization(); - OrganizationDto defaultOrganization = dbTester.getDefaultOrganization(); + OrganizationDto defaultOrganization = db.getDefaultOrganization(); assertThat(organization.getUuid()).isEqualTo(defaultOrganization.getUuid()); assertThat(organization.getKey()).isEqualTo(defaultOrganization.getKey()); assertThat(organization.getName()).isEqualTo(defaultOrganization.getName()); @@ -265,13 +234,13 @@ public class LoadReportAnalysisMetadataHolderStepTest { public void execute_set_organization_from_ce_task_when_organizationKey_is_set_in_report() { reportReader.setMetadata( newBatchReportBuilder() - .setOrganizationKey(dbTester.getDefaultOrganization().getKey()) + .setOrganizationKey(db.getDefaultOrganization().getKey()) .build()); underTest.execute(); Organization organization = analysisMetadataHolder.getOrganization(); - OrganizationDto defaultOrganization = dbTester.getDefaultOrganization(); + OrganizationDto defaultOrganization = db.getDefaultOrganization(); assertThat(organization.getUuid()).isEqualTo(defaultOrganization.getUuid()); assertThat(organization.getKey()).isEqualTo(defaultOrganization.getKey()); assertThat(organization.getName()).isEqualTo(defaultOrganization.getName()); @@ -279,13 +248,15 @@ public class LoadReportAnalysisMetadataHolderStepTest { @Test public void execute_set_non_default_organization_from_ce_task() { - OrganizationDto nonDefaultOrganizationDto = dbTester.organizations().insert(); + OrganizationDto nonDefaultOrganizationDto = db.organizations().insert(); + ComponentDto project = db.components().insertPublicProject(nonDefaultOrganizationDto); reportReader.setMetadata( newBatchReportBuilder() .setOrganizationKey(nonDefaultOrganizationDto.getKey()) + .setProjectKey(project.getDbKey()) .build()); - ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, nonDefaultOrganizationDto.getUuid())); + ComputationStep underTest = createStep(createCeTask(project.getDbKey(), nonDefaultOrganizationDto.getUuid())); underTest.execute(); @@ -297,15 +268,18 @@ public class LoadReportAnalysisMetadataHolderStepTest { @Test public void execute_ensures_that_report_has_quality_profiles_matching_the_project_organization() { - OrganizationDto organization = dbTester.organizations().insert(); + OrganizationDto organization = db.organizations().insert(); + ComponentDto project = db.components().insertPublicProject(organization); ScannerReport.Metadata.Builder metadataBuilder = newBatchReportBuilder(); - metadataBuilder.setOrganizationKey(organization.getKey()); + metadataBuilder + .setOrganizationKey(organization.getKey()) + .setProjectKey(project.getDbKey()); metadataBuilder.getMutableQprofilesPerLanguage().put("js", ScannerReport.Metadata.QProfile.newBuilder().setKey("p1").setName("Sonar way").setLanguage("js").build()); reportReader.setMetadata(metadataBuilder.build()); - dbTester.qualityProfiles().insert(organization, p -> p.setLanguage("js").setKee("p1")); + db.qualityProfiles().insert(organization, p -> p.setLanguage("js").setKee("p1")); - ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, organization.getUuid())); + ComputationStep underTest = createStep(createCeTask(project.getDbKey(), organization.getUuid())); // no errors underTest.execute(); @@ -313,18 +287,21 @@ public class LoadReportAnalysisMetadataHolderStepTest { @Test public void execute_fails_with_MessageException_when_report_has_quality_profiles_on_other_organizations() { - OrganizationDto organization1 = dbTester.organizations().insert(); - OrganizationDto organization2 = dbTester.organizations().insert(); + OrganizationDto organization1 = db.organizations().insert(); + OrganizationDto organization2 = db.organizations().insert(); + ComponentDto projectInOrg1 = db.components().insertPublicProject(organization1); ScannerReport.Metadata.Builder metadataBuilder = newBatchReportBuilder(); - metadataBuilder.setOrganizationKey(organization1.getKey()); + metadataBuilder + .setOrganizationKey(organization1.getKey()) + .setProjectKey(projectInOrg1.getDbKey()); metadataBuilder.getMutableQprofilesPerLanguage().put("js", ScannerReport.Metadata.QProfile.newBuilder().setKey("jsInOrg1").setName("Sonar way").setLanguage("js").build()); metadataBuilder.getMutableQprofilesPerLanguage().put("php", ScannerReport.Metadata.QProfile.newBuilder().setKey("phpInOrg2").setName("PHP way").setLanguage("php").build()); reportReader.setMetadata(metadataBuilder.build()); - dbTester.qualityProfiles().insert(organization1, p -> p.setLanguage("js").setKee("jsInOrg1")); - dbTester.qualityProfiles().insert(organization2, p -> p.setLanguage("php").setKee("phpInOrg2")); + db.qualityProfiles().insert(organization1, p -> p.setLanguage("js").setKee("jsInOrg1")); + db.qualityProfiles().insert(organization2, p -> p.setLanguage("php").setKee("phpInOrg2")); - ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, organization1.getUuid())); + ComputationStep underTest = createStep(createCeTask(projectInOrg1.getDbKey(), organization1.getUuid())); expectedException.expect(MessageException.class); expectedException.expectMessage("Quality profiles with following keys don't exist in organization [" + organization1.getKey() + "]: phpInOrg2"); @@ -334,49 +311,20 @@ public class LoadReportAnalysisMetadataHolderStepTest { @Test public void execute_does_not_fail_when_report_has_a_quality_profile_that_does_not_exist_anymore() { - OrganizationDto organization = dbTester.organizations().insert(); + OrganizationDto organization = db.organizations().insert(); + ComponentDto project = db.components().insertPublicProject(organization); ScannerReport.Metadata.Builder metadataBuilder = newBatchReportBuilder(); - metadataBuilder.setOrganizationKey(organization.getKey()); + metadataBuilder + .setOrganizationKey(organization.getKey()) + .setProjectKey(project.getDbKey()); metadataBuilder.getMutableQprofilesPerLanguage().put("js", ScannerReport.Metadata.QProfile.newBuilder().setKey("p1").setName("Sonar way").setLanguage("js").build()); reportReader.setMetadata(metadataBuilder.build()); - ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, organization.getUuid())); - - underTest.execute(); - } - - @Test - public void execute_fails_with_MessageException_when_organization_is_not_allowed_to_execute_analysis() { - OrganizationDto organization = dbTester.organizations().insert(); - reportReader.setMetadata(newBatchReportBuilder() - .setOrganizationKey(organization.getKey()) - .build()); - ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, organization.getUuid())); - doThrow(new BillingValidationsException("This organization cannot execute project analysis")).when(billingValidations) - .checkOnProjectAnalysis(any(BillingValidations.Organization.class)); - - expectedException.expect(MessageException.class); - expectedException.expectMessage("This organization cannot execute project analysis"); + ComputationStep underTest = createStep(createCeTask(project.getDbKey(), organization.getUuid())); underTest.execute(); } - @Test - public void execute_does_no_fails_when_organization_is_allowed_to_execute_analysis() { - OrganizationDto organization = dbTester.organizations().insert(); - reportReader.setMetadata(newBatchReportBuilder() - .setOrganizationKey(organization.getKey()) - .build()); - ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, organization.getUuid())); - - underTest.execute(); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(BillingValidations.Organization.class); - verify(billingValidations).checkOnProjectAnalysis(argumentCaptor.capture()); - assertThat(argumentCaptor.getValue().getKey()).isEqualTo(organization.getKey()); - assertThat(argumentCaptor.getValue().getUuid()).isEqualTo(organization.getUuid()); - } - @Test public void execute_read_plugins_from_report() { ScannerReport.Metadata.Builder metadataBuilder = newBatchReportBuilder(); @@ -398,7 +346,8 @@ public class LoadReportAnalysisMetadataHolderStepTest { } private LoadReportAnalysisMetadataHolderStep createStep(CeTask ceTask) { - return new LoadReportAnalysisMetadataHolderStep(ceTask, reportReader, analysisMetadataHolder, defaultOrganizationProvider, dbClient, billingValidations, pluginRepository); + return new LoadReportAnalysisMetadataHolderStep(ceTask, reportReader, analysisMetadataHolder, + defaultOrganizationProvider, dbClient, new BranchLoader(analysisMetadataHolder), pluginRepository); } private static ScannerReport.Metadata.Builder newBatchReportBuilder() { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistComponentsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistComponentsStepTest.java index b6998f59d16..fa3e45b5d10 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistComponentsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistComponentsStepTest.java @@ -28,6 +28,7 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDao; import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; +import org.sonar.server.computation.task.projectanalysis.component.BranchPersisterDelegate; import org.sonar.server.computation.task.projectanalysis.component.Component; import org.sonar.server.computation.task.projectanalysis.component.MutableDbIdsRepository; import org.sonar.server.computation.task.projectanalysis.component.MutableDisabledComponentsHolder; @@ -67,6 +68,7 @@ public class PersistComponentsStepTest { mock(MutableDbIdsRepository.class), System2.INSTANCE, mock(MutableDisabledComponentsHolder.class), - mock(AnalysisMetadataHolder.class)).execute(); + mock(AnalysisMetadataHolder.class), + mock(BranchPersisterDelegate.class)).execute(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PurgeDatastoresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PurgeDatastoresStepTest.java index 6264fc0c3d1..a29dc29fe41 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PurgeDatastoresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PurgeDatastoresStepTest.java @@ -134,7 +134,7 @@ public class PurgeDatastoresStepTest extends BaseStepTest { private void verify_call_purge_method_of_the_purge_task(Component project) { treeRootHolder.setRoot(project); - when(settingsRepository.getConfiguration(project)).thenReturn(new MapSettings().asConfig()); + when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().asConfig()); dbIdsRepository.setComponentId(project, PROJECT_ID); underTest.execute(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportPersistComponentsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportPersistComponentsStepTest.java index 5c823ab234d..d013003c1b8 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportPersistComponentsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportPersistComponentsStepTest.java @@ -22,27 +22,36 @@ package org.sonar.server.computation.task.projectanalysis.step; import com.google.common.base.Optional; import java.text.SimpleDateFormat; import java.util.Date; -import java.util.Random; +import java.util.function.Consumer; import java.util.stream.Stream; +import javax.annotation.Nullable; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.System2; +import org.sonar.core.component.ComponentKeys; import org.sonar.db.DbClient; 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.organization.OrganizationDto; +import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; +import org.sonar.server.computation.task.projectanalysis.analysis.Branch; +import org.sonar.server.computation.task.projectanalysis.analysis.Project; +import org.sonar.server.computation.task.projectanalysis.component.BranchPersisterDelegate; import org.sonar.server.computation.task.projectanalysis.component.Component; import org.sonar.server.computation.task.projectanalysis.component.FileAttributes; +import org.sonar.server.computation.task.projectanalysis.component.MainBranchImpl; import org.sonar.server.computation.task.projectanalysis.component.MutableDbIdsRepositoryRule; import org.sonar.server.computation.task.projectanalysis.component.MutableDisabledComponentsHolder; import org.sonar.server.computation.task.projectanalysis.component.ReportComponent; import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule; import org.sonar.server.computation.task.step.ComputationStep; +import static org.apache.commons.lang.StringUtils.isEmpty; +import static org.apache.commons.lang.StringUtils.trimToNull; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.guava.api.Assertions.assertThat; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; @@ -52,7 +61,6 @@ import static org.sonar.db.component.ComponentDto.UUID_PATH_OF_ROOT; import static org.sonar.db.component.ComponentDto.UUID_PATH_SEPARATOR; import static org.sonar.db.component.ComponentTesting.newDirectory; import static org.sonar.db.component.ComponentTesting.newModuleDto; -import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.DIRECTORY; import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.FILE; import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT; @@ -66,7 +74,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { private static final String ORGANIZATION_UUID = "org1"; @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); + public DbTester db = DbTester.create(System2.INSTANCE); @Rule public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); @Rule @@ -76,18 +84,19 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { .setOrganizationUuid(ORGANIZATION_UUID); private System2 system2 = mock(System2.class); - private DbClient dbClient = dbTester.getDbClient(); + private DbClient dbClient = db.getDbClient(); private Date now; private MutableDisabledComponentsHolder disabledComponentsHolder = mock(MutableDisabledComponentsHolder.class, RETURNS_DEEP_STUBS); private PersistComponentsStep underTest; + private BranchPersisterDelegate branchPersister; @Before public void setup() throws Exception { now = DATE_FORMAT.parse("2015-06-02"); when(system2.now()).thenReturn(now.getTime()); - dbTester.organizations().insertForUuid(ORGANIZATION_UUID); - underTest = new PersistComponentsStep(dbClient, treeRootHolder, dbIdsRepository, system2, disabledComponentsHolder, analysisMetadataHolder); + db.organizations().insertForUuid(ORGANIZATION_UUID); + underTest = new PersistComponentsStep(dbClient, treeRootHolder, dbIdsRepository, system2, disabledComponentsHolder, analysisMetadataHolder, branchPersister); } @Override @@ -97,7 +106,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { @Test public void persist_components() { - ComponentDto projectDto = insertProject(); + ComponentDto projectDto = prepareProject(); Component file = builder(FILE, 4).setUuid("DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java") .setPath("src/main/java/dir/Foo.java") .setFileAttributes(new FileAttributes(false, "java", 1)) @@ -119,9 +128,9 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { underTest.execute(); - assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4); + assertThat(db.countRowsOfTable("projects")).isEqualTo(4); - ComponentDto moduleDto = dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get(); + ComponentDto moduleDto = dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get(); assertThat(moduleDto.getOrganizationUuid()).isEqualTo(ORGANIZATION_UUID); assertThat(moduleDto.name()).isEqualTo("Module"); assertThat(moduleDto.description()).isEqualTo("Module description"); @@ -137,7 +146,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { assertThat(moduleDto.getRootUuid()).isEqualTo(projectDto.uuid()); assertThat(moduleDto.getCreatedAt()).isEqualTo(now); - ComponentDto directoryDto = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get(); + ComponentDto directoryDto = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir").get(); assertThat(directoryDto.getOrganizationUuid()).isEqualTo(ORGANIZATION_UUID); assertThat(directoryDto.name()).isEqualTo("src/main/java/dir"); assertThat(directoryDto.description()).isNull(); @@ -153,7 +162,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { assertThat(directoryDto.getRootUuid()).isEqualTo(moduleDto.uuid()); assertThat(directoryDto.getCreatedAt()).isEqualTo(now); - ComponentDto fileDto = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); + ComponentDto fileDto = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); assertThat(fileDto.getOrganizationUuid()).isEqualTo(ORGANIZATION_UUID); assertThat(fileDto.name()).isEqualTo("Foo.java"); assertThat(fileDto.description()).isNull(); @@ -175,33 +184,113 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { assertThat(dbIdsRepository.getComponentId(file)).isEqualTo(fileDto.getId()); } + @Test + public void persist_components_of_existing_branch() { + ComponentDto project = prepareBranch("feature/foo"); + Component file = builder(FILE, 4).setUuid("DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java") + .setPath("src/main/java/dir/Foo.java") + .setFileAttributes(new FileAttributes(false, "java", 1)) + .build(); + Component directory = builder(DIRECTORY, 3).setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir") + .setPath("src/main/java/dir") + .addChildren(file) + .build(); + Component module = builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY) + .setPath("module") + .setName("Module") + .setDescription("Module description") + .addChildren(directory) + .build(); + Component treeRoot = asTreeRoot(project) + .addChildren(module) + .build(); + treeRootHolder.setRoot(treeRoot); + + underTest.execute(); + + assertThat(db.countRowsOfTable("projects")).isEqualTo(4); + + ComponentDto moduleDto = dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get(); + assertThat(moduleDto.getOrganizationUuid()).isEqualTo(ORGANIZATION_UUID); + assertThat(moduleDto.name()).isEqualTo("Module"); + assertThat(moduleDto.description()).isEqualTo("Module description"); + assertThat(moduleDto.path()).isEqualTo("module"); + assertThat(moduleDto.uuid()).isEqualTo("BCDE"); + assertThat(moduleDto.getUuidPath()).isEqualTo(project.getUuidPath() + project.uuid() + UUID_PATH_SEPARATOR); + assertThat(moduleDto.moduleUuid()).isEqualTo(project.uuid()); + assertThat(moduleDto.moduleUuidPath()).isEqualTo(project.moduleUuidPath() + moduleDto.uuid() + "."); + assertThat(moduleDto.getMainBranchProjectUuid()).isEqualTo(project.uuid()); + assertThat(moduleDto.projectUuid()).isEqualTo(project.uuid()); + assertThat(moduleDto.qualifier()).isEqualTo("BRC"); + assertThat(moduleDto.scope()).isEqualTo("PRJ"); + assertThat(moduleDto.getRootUuid()).isEqualTo(project.uuid()); + assertThat(moduleDto.getCreatedAt()).isEqualTo(now); + + ComponentDto directoryDto = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir").get(); + assertThat(directoryDto.getOrganizationUuid()).isEqualTo(ORGANIZATION_UUID); + assertThat(directoryDto.name()).isEqualTo("src/main/java/dir"); + assertThat(directoryDto.description()).isNull(); + assertThat(directoryDto.path()).isEqualTo("src/main/java/dir"); + assertThat(directoryDto.uuid()).isEqualTo("CDEF"); + assertThat(directoryDto.getUuidPath()).isEqualTo(moduleDto.getUuidPath() + moduleDto.uuid() + UUID_PATH_SEPARATOR); + assertThat(directoryDto.moduleUuid()).isEqualTo(moduleDto.uuid()); + assertThat(directoryDto.moduleUuidPath()).isEqualTo(moduleDto.moduleUuidPath()); + assertThat(directoryDto.getMainBranchProjectUuid()).isEqualTo(project.uuid()); + assertThat(directoryDto.projectUuid()).isEqualTo(project.uuid()); + assertThat(directoryDto.qualifier()).isEqualTo("DIR"); + assertThat(directoryDto.scope()).isEqualTo("DIR"); + assertThat(directoryDto.getRootUuid()).isEqualTo(moduleDto.uuid()); + assertThat(directoryDto.getCreatedAt()).isEqualTo(now); + + ComponentDto fileDto = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); + assertThat(fileDto.getOrganizationUuid()).isEqualTo(ORGANIZATION_UUID); + assertThat(fileDto.name()).isEqualTo("Foo.java"); + assertThat(fileDto.description()).isNull(); + assertThat(fileDto.path()).isEqualTo("src/main/java/dir/Foo.java"); + assertThat(fileDto.language()).isEqualTo("java"); + assertThat(fileDto.uuid()).isEqualTo("DEFG"); + assertThat(fileDto.getUuidPath()).isEqualTo(directoryDto.getUuidPath() + directoryDto.uuid() + UUID_PATH_SEPARATOR); + assertThat(fileDto.moduleUuid()).isEqualTo(moduleDto.uuid()); + assertThat(fileDto.moduleUuidPath()).isEqualTo(moduleDto.moduleUuidPath()); + assertThat(fileDto.getMainBranchProjectUuid()).isEqualTo(project.uuid()); + assertThat(fileDto.projectUuid()).isEqualTo(project.uuid()); + assertThat(fileDto.qualifier()).isEqualTo("FIL"); + assertThat(fileDto.scope()).isEqualTo("FIL"); + assertThat(fileDto.getRootUuid()).isEqualTo(moduleDto.uuid()); + assertThat(fileDto.getCreatedAt()).isEqualTo(now); + + assertThat(dbIdsRepository.getComponentId(module)).isEqualTo(moduleDto.getId()); + assertThat(dbIdsRepository.getComponentId(directory)).isEqualTo(directoryDto.getId()); + assertThat(dbIdsRepository.getComponentId(file)).isEqualTo(fileDto.getId()); + } + @Test public void persist_file_directly_attached_on_root_directory() { - ComponentDto projectDto = insertProject(); + ComponentDto projectDto = prepareProject(); treeRootHolder.setRoot( asTreeRoot(projectDto) .addChildren( - builder(DIRECTORY, 2).setUuid("CDEF").setKey(PROJECT_KEY + ":/").setPath("/") + builder(DIRECTORY, 2).setUuid("CDEF").setKey(projectDto.getDbKey() + ":/").setPath("/") .addChildren( - builder(FILE, 3).setUuid("DEFG").setKey(PROJECT_KEY + ":pom.xml").setPath("pom.xml") + builder(FILE, 3).setUuid("DEFG").setKey(projectDto.getDbKey() + ":pom.xml").setPath("pom.xml") .build()) .build()) .build()); underTest.execute(); - ComponentDto directory = dbClient.componentDao().selectByKey(dbTester.getSession(), "PROJECT_KEY:/").get(); + ComponentDto directory = dbClient.componentDao().selectByKey(db.getSession(), projectDto.getDbKey() + ":/").get(); assertThat(directory.name()).isEqualTo("/"); assertThat(directory.path()).isEqualTo("/"); - ComponentDto file = dbClient.componentDao().selectByKey(dbTester.getSession(), "PROJECT_KEY:pom.xml").get(); + ComponentDto file = dbClient.componentDao().selectByKey(db.getSession(), projectDto.getDbKey() + ":pom.xml").get(); assertThat(file.name()).isEqualTo("pom.xml"); assertThat(file.path()).isEqualTo("pom.xml"); } @Test public void persist_unit_test() { - ComponentDto projectDto = insertProject(); + ComponentDto projectDto = prepareProject(); treeRootHolder.setRoot( asTreeRoot(projectDto) .addChildren( @@ -217,7 +306,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { underTest.execute(); - ComponentDto file = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY + ":src/test/java/dir/FooTest.java").get(); + ComponentDto file = dbClient.componentDao().selectByKey(db.getSession(), PROJECT_KEY + ":src/test/java/dir/FooTest.java").get(); assertThat(file.name()).isEqualTo("FooTest.java"); assertThat(file.path()).isEqualTo("src/test/java/dir/FooTest.java"); assertThat(file.qualifier()).isEqualTo("UTS"); @@ -227,14 +316,13 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { @Test public void persist_only_new_components() { // Project and module already exists - ComponentDto project = newPrivateProjectDto(dbTester.getDefaultOrganization(), "ABCD").setDbKey(PROJECT_KEY).setName("Project"); - dbClient.componentDao().insert(dbTester.getSession(), project); + ComponentDto project = prepareProject(); ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setDbKey(MODULE_KEY).setName("Module"); - dbClient.componentDao().insert(dbTester.getSession(), module); - dbTester.getSession().commit(); + dbClient.componentDao().insert(db.getSession(), module); + db.getSession().commit(); treeRootHolder.setRoot( - builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) + builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()) .setName("Project") .addChildren( builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY) @@ -252,15 +340,15 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { underTest.execute(); - assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4); + assertThat(db.countRowsOfTable("projects")).isEqualTo(4); - ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get(); + ComponentDto projectReloaded = dbClient.componentDao().selectByKey(db.getSession(), project.getDbKey()).get(); assertThat(projectReloaded.getId()).isEqualTo(project.getId()); assertThat(projectReloaded.uuid()).isEqualTo(project.uuid()); assertThat(projectReloaded.getUuidPath()).isEqualTo(UUID_PATH_OF_ROOT); assertThat(projectReloaded.getMainBranchProjectUuid()).isNull(); - ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get(); + ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get(); assertThat(moduleReloaded.getId()).isEqualTo(module.getId()); assertThat(moduleReloaded.uuid()).isEqualTo(module.uuid()); assertThat(moduleReloaded.getUuidPath()).isEqualTo(module.getUuidPath()); @@ -270,7 +358,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { assertThat(moduleReloaded.getRootUuid()).isEqualTo(module.getRootUuid()); assertThat(moduleReloaded.getMainBranchProjectUuid()).isNull(); - ComponentDto directory = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get(); + ComponentDto directory = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir").get(); assertThat(directory.getUuidPath()).isEqualTo(directory.getUuidPath()); assertThat(directory.moduleUuid()).isEqualTo(module.uuid()); assertThat(directory.moduleUuidPath()).isEqualTo(module.moduleUuidPath()); @@ -278,7 +366,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { assertThat(directory.getRootUuid()).isEqualTo(module.uuid()); assertThat(directory.getMainBranchProjectUuid()).isNull(); - ComponentDto file = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); + ComponentDto file = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); assertThat(file.getUuidPath()).isEqualTo(file.getUuidPath()); assertThat(file.moduleUuid()).isEqualTo(module.uuid()); assertThat(file.moduleUuidPath()).isEqualTo(module.moduleUuidPath()); @@ -289,7 +377,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { @Test public void compute_root_uuid() { - ComponentDto project = insertProject(); + ComponentDto project = prepareProject(); treeRootHolder.setRoot( asTreeRoot(project) .addChildren( @@ -312,36 +400,28 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { underTest.execute(); - assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5); + assertThat(db.countRowsOfTable("projects")).isEqualTo(5); - Optional module = dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY); + Optional module = dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY); assertThat(module).isPresent(); assertThat(module.get().getRootUuid()).isEqualTo(project.uuid()); - Optional subModule1 = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_1_KEY"); + Optional subModule1 = dbClient.componentDao().selectByKey(db.getSession(), "SUB_MODULE_1_KEY"); assertThat(subModule1).isPresent(); assertThat(subModule1.get().getRootUuid()).isEqualTo(project.uuid()); - Optional subModule2 = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_2_KEY"); + Optional subModule2 = dbClient.componentDao().selectByKey(db.getSession(), "SUB_MODULE_2_KEY"); assertThat(subModule2).isPresent(); assertThat(subModule2.get().getRootUuid()).isEqualTo(project.uuid()); - Optional directory = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_2_KEY:src/main/java/dir"); + Optional directory = dbClient.componentDao().selectByKey(db.getSession(), "SUB_MODULE_2_KEY:src/main/java/dir"); assertThat(directory).isPresent(); assertThat(directory.get().getRootUuid()).isEqualTo(subModule2.get().uuid()); } - private ReportComponent.Builder asTreeRoot(ComponentDto project) { - return builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()).setName(project.name()); - } - - public ComponentDto insertProject() { - return dbTester.components().insertPrivateProject(dbTester.organizations().insert()); - } - @Test public void persist_multi_modules() { - ComponentDto project = insertProject(); + ComponentDto project = prepareProject(); treeRootHolder.setRoot( asTreeRoot(project) .setName("Project") @@ -360,21 +440,21 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { underTest.execute(); - assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4); + assertThat(db.countRowsOfTable("projects")).isEqualTo(4); - ComponentDto moduleA = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_A").get(); + ComponentDto moduleA = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_A").get(); assertThat(moduleA.getUuidPath()).isEqualTo(project.getUuidPath() + project.uuid() + UUID_PATH_SEPARATOR); assertThat(moduleA.moduleUuid()).isEqualTo(project.uuid()); assertThat(moduleA.moduleUuidPath()).isEqualTo(project.moduleUuidPath() + moduleA.uuid() + "."); assertThat(moduleA.getRootUuid()).isEqualTo(project.uuid()); - ComponentDto subModuleA = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_A").get(); + ComponentDto subModuleA = dbClient.componentDao().selectByKey(db.getSession(), "SUB_MODULE_A").get(); assertThat(subModuleA.getUuidPath()).isEqualTo(moduleA.getUuidPath() + moduleA.uuid() + UUID_PATH_SEPARATOR); assertThat(subModuleA.moduleUuid()).isEqualTo(moduleA.uuid()); assertThat(subModuleA.moduleUuidPath()).isEqualTo(moduleA.moduleUuidPath() + subModuleA.uuid() + "."); assertThat(subModuleA.getRootUuid()).isEqualTo(project.uuid()); - ComponentDto moduleB = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B").get(); + ComponentDto moduleB = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_B").get(); assertThat(moduleB.getUuidPath()).isEqualTo(project.getUuidPath() + project.uuid() + UUID_PATH_SEPARATOR); assertThat(moduleB.moduleUuid()).isEqualTo(project.uuid()); assertThat(moduleB.moduleUuidPath()).isEqualTo(project.moduleUuidPath() + moduleB.uuid() + "."); @@ -383,18 +463,17 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { @Test public void nothing_to_persist() { - ComponentDto project = newPrivateProjectDto(dbTester.organizations().insert(), "ABCD").setDbKey(PROJECT_KEY).setName("Project"); - dbClient.componentDao().insert(dbTester.getSession(), project); + ComponentDto project = prepareProject(); ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setDbKey(MODULE_KEY).setName("Module"); - dbClient.componentDao().insert(dbTester.getSession(), module); + dbClient.componentDao().insert(db.getSession(), module); ComponentDto directory = ComponentTesting.newDirectory(module, "src/main/java/dir").setUuid("CDEF").setDbKey("MODULE_KEY:src/main/java/dir"); ComponentDto file = ComponentTesting.newFileDto(module, directory, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java") .setDbKey("MODULE_KEY:src/main/java/dir/Foo.java"); - dbClient.componentDao().insert(dbTester.getSession(), directory, file); - dbTester.getSession().commit(); + dbClient.componentDao().insert(db.getSession(), directory, file); + db.getSession().commit(); treeRootHolder.setRoot( - builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) + builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()) .setName("Project") .addChildren( builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY) @@ -412,13 +491,13 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { underTest.execute(); - assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4); - assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get().getId()).isEqualTo(project.getId()); - assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get().getId()).isEqualTo(module.getId()); - assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get().getId()).isEqualTo(directory.getId()); - assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get().getId()).isEqualTo(file.getId()); + assertThat(db.countRowsOfTable("projects")).isEqualTo(4); + assertThat(dbClient.componentDao().selectByKey(db.getSession(), project.getDbKey()).get().getId()).isEqualTo(project.getId()); + assertThat(dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get().getId()).isEqualTo(module.getId()); + assertThat(dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir").get().getId()).isEqualTo(directory.getId()); + assertThat(dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get().getId()).isEqualTo(file.getId()); - ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get(); + ComponentDto projectReloaded = dbClient.componentDao().selectByKey(db.getSession(), project.getDbKey()).get(); assertThat(projectReloaded.getId()).isEqualTo(project.getId()); assertThat(projectReloaded.uuid()).isEqualTo(project.uuid()); assertThat(projectReloaded.moduleUuid()).isEqualTo(project.moduleUuid()); @@ -426,7 +505,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { assertThat(projectReloaded.projectUuid()).isEqualTo(project.projectUuid()); assertThat(projectReloaded.getRootUuid()).isEqualTo(project.getRootUuid()); - ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get(); + ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get(); assertThat(moduleReloaded.getId()).isEqualTo(module.getId()); assertThat(moduleReloaded.uuid()).isEqualTo(module.uuid()); assertThat(moduleReloaded.getUuidPath()).isEqualTo(module.getUuidPath()); @@ -435,7 +514,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { assertThat(moduleReloaded.projectUuid()).isEqualTo(module.projectUuid()); assertThat(moduleReloaded.getRootUuid()).isEqualTo(module.getRootUuid()); - ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get(); + ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir").get(); assertThat(directoryReloaded.uuid()).isEqualTo(directory.uuid()); assertThat(directoryReloaded.getUuidPath()).isEqualTo(directory.getUuidPath()); assertThat(directoryReloaded.moduleUuid()).isEqualTo(directory.moduleUuid()); @@ -445,7 +524,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { assertThat(directoryReloaded.name()).isEqualTo(directory.name()); assertThat(directoryReloaded.path()).isEqualTo(directory.path()); - ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); + ComponentDto fileReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); assertThat(fileReloaded.uuid()).isEqualTo(file.uuid()); assertThat(fileReloaded.getUuidPath()).isEqualTo(file.getUuidPath()); assertThat(fileReloaded.moduleUuid()).isEqualTo(file.moduleUuid()); @@ -458,14 +537,15 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { @Test public void update_module_name_and_description() { - ComponentDto project = newPrivateProjectDto(dbTester.getDefaultOrganization(), "ABCD").setDbKey(PROJECT_KEY).setName("Project").setDescription("Project description"); - dbClient.componentDao().insert(dbTester.getSession(), project); + ComponentDto project = prepareProject(p -> p.setName("Project").setDescription("Project description")); ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setDbKey(MODULE_KEY).setName("Module"); - dbClient.componentDao().insert(dbTester.getSession(), module); - dbTester.getSession().commit(); + dbClient.componentDao().insert(db.getSession(), module); + db.getSession().commit(); treeRootHolder.setRoot( - builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) + builder(PROJECT, 1) + .setUuid(project.uuid()) + .setKey(project.getDbKey()) .setName("New Project") .setDescription("New project description") .addChildren( @@ -480,31 +560,30 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { underTest.execute(); // functional transaction not finished, "A-fields" are not updated yet - assertNameAndDescription(PROJECT_KEY, "Project", "Project description"); + assertNameAndDescription(project.getDbKey(), "Project", "Project description"); assertNameAndDescription(MODULE_KEY, "Module", null); // commit functional transaction -> copies B-fields to A-fields - dbClient.componentDao().applyBChangesForRootComponentUuid(dbTester.getSession(), "ABCD"); - assertNameAndDescription(PROJECT_KEY, "New Project", "New project description"); + dbClient.componentDao().applyBChangesForRootComponentUuid(db.getSession(), project.uuid()); + assertNameAndDescription(project.getDbKey(), "New Project", "New project description"); assertNameAndDescription(MODULE_KEY, "New Module", "New module description"); } private void assertNameAndDescription(String key, String expectedName, String expectedDescription) { - ComponentDto dto = dbClient.componentDao().selectByKey(dbTester.getSession(), key).get(); + ComponentDto dto = dbClient.componentDao().selectByKey(db.getSession(), key).get(); assertThat(dto.name()).isEqualTo(expectedName); assertThat(dto.description()).isEqualTo(expectedDescription); } @Test public void update_module_path() { - ComponentDto project = newPrivateProjectDto(dbTester.organizations().insert(), "ABCD").setDbKey(PROJECT_KEY).setName("Project"); - dbClient.componentDao().insert(dbTester.getSession(), project); + ComponentDto project = prepareProject(); ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setDbKey(MODULE_KEY).setName("Module").setPath("path"); - dbClient.componentDao().insert(dbTester.getSession(), module); - dbTester.getSession().commit(); + dbClient.componentDao().insert(db.getSession(), module); + db.getSession().commit(); treeRootHolder.setRoot( - builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) + builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()) .setName("Project") .addChildren( builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY) @@ -515,32 +594,31 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { underTest.execute(); - assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get().path()).isEqualTo("path"); + assertThat(dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get().path()).isEqualTo("path"); // commit the functional transaction - dbClient.componentDao().applyBChangesForRootComponentUuid(dbTester.getSession(), project.uuid()); - assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get().path()).isEqualTo("New path"); + dbClient.componentDao().applyBChangesForRootComponentUuid(db.getSession(), project.uuid()); + assertThat(dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get().path()).isEqualTo("New path"); } @Test public void update_module_uuid_when_moving_a_module() { - ComponentDto project = newPrivateProjectDto(dbTester.getDefaultOrganization(), "ABCD").setDbKey(PROJECT_KEY).setName("Project"); - dbClient.componentDao().insert(dbTester.getSession(), project); + ComponentDto project = prepareProject(); ComponentDto moduleA = ComponentTesting.newModuleDto("EDCB", project) .setDbKey("MODULE_A") .setName("Module A"); ComponentDto moduleB = ComponentTesting.newModuleDto("BCDE", project) .setDbKey("MODULE_B") .setName("Module B"); - dbClient.componentDao().insert(dbTester.getSession(), moduleA, moduleB); + dbClient.componentDao().insert(db.getSession(), moduleA, moduleB); ComponentDto directory = ComponentTesting.newDirectory(moduleB, "src/main/java/dir").setUuid("CDEF").setDbKey("MODULE_B:src/main/java/dir"); ComponentDto file = ComponentTesting.newFileDto(moduleB, directory, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java") .setDbKey("MODULE_B:src/main/java/dir/Foo.java"); - dbClient.componentDao().insert(dbTester.getSession(), directory, file); - dbTester.getSession().commit(); + dbClient.componentDao().insert(db.getSession(), directory, file); + db.getSession().commit(); treeRootHolder.setRoot( - builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) + builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()) .setName("Project") .addChildren( builder(Component.Type.MODULE, 2).setUuid("EDCB").setKey("MODULE_A") @@ -563,14 +641,14 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { underTest.execute(); // commit the functional transaction - dbClient.componentDao().applyBChangesForRootComponentUuid(dbTester.getSession(), project.uuid()); - dbTester.commit(); + dbClient.componentDao().applyBChangesForRootComponentUuid(db.getSession(), project.uuid()); + db.commit(); - assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5); + assertThat(db.countRowsOfTable("projects")).isEqualTo(5); - ComponentDto moduleAreloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_A").get(); + ComponentDto moduleAreloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_A").get(); - ComponentDto moduleBReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B").get(); + ComponentDto moduleBReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_B").get(); assertThat(moduleBReloaded).isNotNull(); assertThat(moduleBReloaded.uuid()).isEqualTo(moduleB.uuid()); assertThat(moduleBReloaded.getUuidPath()).isEqualTo(moduleBReloaded.getUuidPath()); @@ -579,7 +657,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { assertThat(moduleBReloaded.projectUuid()).isEqualTo(project.uuid()); assertThat(moduleBReloaded.getRootUuid()).isEqualTo(project.uuid()); - ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B:src/main/java/dir").get(); + ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_B:src/main/java/dir").get(); assertThat(directoryReloaded).isNotNull(); assertThat(directoryReloaded.uuid()).isEqualTo(directory.uuid()); assertThat(directoryReloaded.getUuidPath()).isEqualTo(directoryReloaded.getUuidPath()); @@ -588,7 +666,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { assertThat(directoryReloaded.projectUuid()).isEqualTo(project.uuid()); assertThat(directoryReloaded.getRootUuid()).isEqualTo(moduleBReloaded.uuid()); - ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B:src/main/java/dir/Foo.java").get(); + ComponentDto fileReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_B:src/main/java/dir/Foo.java").get(); assertThat(fileReloaded).isNotNull(); assertThat(fileReloaded.uuid()).isEqualTo(file.uuid()); assertThat(fileReloaded.getUuidPath()).isEqualTo(fileReloaded.getUuidPath()); @@ -601,31 +679,29 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { @Test public void do_not_update_created_at_on_existing_component() { Date oldDate = DateUtils.parseDate("2015-01-01"); - ComponentDto project = newPrivateProjectDto(dbTester.getDefaultOrganization(), "ABCD").setDbKey(PROJECT_KEY).setName("Project").setCreatedAt(oldDate); - dbClient.componentDao().insert(dbTester.getSession(), project); + ComponentDto project = prepareProject(p -> p.setCreatedAt(oldDate)); ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setDbKey(MODULE_KEY).setName("Module").setPath("path").setCreatedAt(oldDate); - dbClient.componentDao().insert(dbTester.getSession(), module); - dbTester.getSession().commit(); + dbClient.componentDao().insert(db.getSession(), module); + db.getSession().commit(); treeRootHolder.setRoot( - builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) + builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()) .build()); underTest.execute(); - Optional projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY); + Optional projectReloaded = dbClient.componentDao().selectByUuid(db.getSession(), project.uuid()); assertThat(projectReloaded.get().getCreatedAt()).isNotEqualTo(now); } @Test public void persist_components_that_were_previously_removed() { - ComponentDto project = newPrivateProjectDto(dbTester.organizations().insert(), "ABCD").setDbKey(PROJECT_KEY).setName("Project"); - dbClient.componentDao().insert(dbTester.getSession(), project); + ComponentDto project = prepareProject(); ComponentDto removedModule = ComponentTesting.newModuleDto("BCDE", project) .setDbKey(MODULE_KEY) .setName("Module") .setEnabled(false); - dbClient.componentDao().insert(dbTester.getSession(), removedModule); + dbClient.componentDao().insert(db.getSession(), removedModule); ComponentDto removedDirectory = ComponentTesting.newDirectory(removedModule, "src/main/java/dir") .setUuid("CDEF") .setDbKey("MODULE_KEY:src/main/java/dir") @@ -635,11 +711,11 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { .setName("Foo.java") .setDbKey("MODULE_KEY:src/main/java/dir/Foo.java") .setEnabled(false); - dbClient.componentDao().insert(dbTester.getSession(), removedDirectory, removedFile); - dbTester.getSession().commit(); + dbClient.componentDao().insert(db.getSession(), removedDirectory, removedFile); + db.getSession().commit(); treeRootHolder.setRoot( - builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) + builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()) .setName("Project") .addChildren( builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY) @@ -657,17 +733,17 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { underTest.execute(); - assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4); - assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get().getId()).isEqualTo(project.getId()); - assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get().getId()).isEqualTo(removedModule.getId()); - assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get().getId()).isEqualTo(removedDirectory.getId()); - assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get().getId()).isEqualTo(removedFile.getId()); + assertThat(db.countRowsOfTable("projects")).isEqualTo(4); + assertThat(dbClient.componentDao().selectByKey(db.getSession(), project.getDbKey()).get().getId()).isEqualTo(project.getId()); + assertThat(dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get().getId()).isEqualTo(removedModule.getId()); + assertThat(dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir").get().getId()).isEqualTo(removedDirectory.getId()); + assertThat(dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get().getId()).isEqualTo(removedFile.getId()); assertExistButDisabled(removedModule.getDbKey(), removedDirectory.getDbKey(), removedFile.getDbKey()); // commit the functional transaction - dbClient.componentDao().applyBChangesForRootComponentUuid(dbTester.getSession(), project.uuid()); + dbClient.componentDao().applyBChangesForRootComponentUuid(db.getSession(), project.uuid()); - ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get(); + ComponentDto projectReloaded = dbClient.componentDao().selectByKey(db.getSession(), project.getDbKey()).get(); assertThat(projectReloaded.getId()).isEqualTo(project.getId()); assertThat(projectReloaded.uuid()).isEqualTo(project.uuid()); assertThat(projectReloaded.getUuidPath()).isEqualTo(project.getUuidPath()); @@ -677,7 +753,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { assertThat(projectReloaded.getRootUuid()).isEqualTo(project.getRootUuid()); assertThat(projectReloaded.isEnabled()).isTrue(); - ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get(); + ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get(); assertThat(moduleReloaded.getId()).isEqualTo(removedModule.getId()); assertThat(moduleReloaded.uuid()).isEqualTo(removedModule.uuid()); assertThat(moduleReloaded.getUuidPath()).isEqualTo(removedModule.getUuidPath()); @@ -687,7 +763,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { assertThat(moduleReloaded.getRootUuid()).isEqualTo(removedModule.getRootUuid()); assertThat(moduleReloaded.isEnabled()).isTrue(); - ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get(); + ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir").get(); assertThat(directoryReloaded.getId()).isEqualTo(removedDirectory.getId()); assertThat(directoryReloaded.uuid()).isEqualTo(removedDirectory.uuid()); assertThat(directoryReloaded.getUuidPath()).isEqualTo(removedDirectory.getUuidPath()); @@ -699,7 +775,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { assertThat(directoryReloaded.path()).isEqualTo(removedDirectory.path()); assertThat(directoryReloaded.isEnabled()).isTrue(); - ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); + ComponentDto fileReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); assertThat(fileReloaded.getId()).isEqualTo(fileReloaded.getId()); assertThat(fileReloaded.uuid()).isEqualTo(removedFile.uuid()); assertThat(fileReloaded.getUuidPath()).isEqualTo(removedFile.getUuidPath()); @@ -714,27 +790,26 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { private void assertExistButDisabled(String... keys) { for (String key : keys) { - ComponentDto dto = dbClient.componentDao().selectByKey(dbTester.getSession(), key).get(); + ComponentDto dto = dbClient.componentDao().selectByKey(db.getSession(), key).get(); assertThat(dto.isEnabled()).isFalse(); } } @Test public void update_module_uuid_when_reactivating_removed_component() { - ComponentDto project = newPrivateProjectDto(dbTester.getDefaultOrganization(), "ABCD").setDbKey(PROJECT_KEY).setName("Project"); - dbClient.componentDao().insert(dbTester.getSession(), project); + ComponentDto project = prepareProject(); ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setDbKey(MODULE_KEY).setName("Module"); ComponentDto removedModule = ComponentTesting.newModuleDto("EDCD", project).setDbKey("REMOVED_MODULE_KEY").setName("Removed Module").setEnabled(false); - dbClient.componentDao().insert(dbTester.getSession(), module, removedModule); + dbClient.componentDao().insert(db.getSession(), module, removedModule); ComponentDto directory = ComponentTesting.newDirectory(module, "src/main/java/dir").setUuid("CDEF").setDbKey("MODULE_KEY:src/main/java/dir"); // The file was attached to another module ComponentDto removedFile = ComponentTesting.newFileDto(removedModule, directory, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java") .setDbKey("MODULE_KEY:src/main/java/dir/Foo.java").setEnabled(false); - dbClient.componentDao().insert(dbTester.getSession(), directory, removedFile); - dbTester.getSession().commit(); + dbClient.componentDao().insert(db.getSession(), directory, removedFile); + db.getSession().commit(); treeRootHolder.setRoot( - builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) + builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()) .setName("Project") .addChildren( builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY) @@ -753,15 +828,15 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { underTest.execute(); // commit the functional transaction - dbClient.componentDao().applyBChangesForRootComponentUuid(dbTester.getSession(), project.uuid()); - dbTester.commit(); + dbClient.componentDao().applyBChangesForRootComponentUuid(db.getSession(), project.uuid()); + db.commit(); // Projects contains 4 components from the report + one removed module - assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5); + assertThat(db.countRowsOfTable("projects")).isEqualTo(5); - ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get(); + ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get(); - ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); + ComponentDto fileReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); assertThat(fileReloaded.getId()).isEqualTo(removedFile.getId()); assertThat(fileReloaded.uuid()).isEqualTo(removedFile.uuid()); assertThat(fileReloaded.getUuidPath()).isEqualTo(fileReloaded.getUuidPath()); @@ -775,21 +850,18 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { @Test public void persists_existing_components_with_visibility_of_root_in_db_out_of_functional_transaction() { - boolean isRootPrivate = new Random().nextBoolean(); - OrganizationDto organization = dbTester.organizations().insert(); - ComponentDto project = newPrivateProjectDto(organization, "ABCD").setDbKey(PROJECT_KEY).setName("Project").setPrivate(isRootPrivate); - dbTester.components().insertComponent(project); - ComponentDto module = newModuleDto(project).setUuid("BCDE").setDbKey("MODULE").setPrivate(!isRootPrivate); - dbTester.components().insertComponent(module); - dbTester.components().insertComponent(newDirectory(module, "DEFG", "Directory").setDbKey("DIR").setPrivate(isRootPrivate)); + ComponentDto project = prepareProject(p -> p.setPrivate(true)); + ComponentDto module = newModuleDto(project).setPrivate(false); + db.components().insertComponent(module); + ComponentDto dir = db.components().insertComponent(newDirectory(module, "DEFG", "Directory").setDbKey("DIR").setPrivate(true)); treeRootHolder.setRoot(createSampleProjectComponentTree(project)); underTest.execute(); - Stream.of("ABCD", "BCDE", "BCDE", "BCDE") - .forEach(uuid -> assertThat(dbClient.componentDao().selectByUuid(dbTester.getSession(), uuid).get().isPrivate()) + Stream.of(project.uuid(), module.uuid(), dir.uuid()) + .forEach(uuid -> assertThat(dbClient.componentDao().selectByUuid(db.getSession(), uuid).get().isPrivate()) .describedAs("for uuid " + uuid) - .isEqualTo(isRootPrivate)); + .isEqualTo(true)); } private ReportComponent createSampleProjectComponentTree(ComponentDto project) { @@ -813,4 +885,59 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { .build()) .build(); } + + private ReportComponent.Builder asTreeRoot(ComponentDto project) { + return builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()).setName(project.name()); + } + + private ComponentDto prepareProject(Consumer... populators) { + ComponentDto dto = db.components().insertPrivateProject(db.organizations().insert(), populators); + analysisMetadataHolder.setProject(Project.copyOf(dto)); + analysisMetadataHolder.setBranch(new MainBranchImpl(null)); + return dto; + } + + private ComponentDto prepareBranch(String branchName, Consumer... populators) { + ComponentDto dto = db.components().insertPrivateProject(db.organizations().insert(), populators); + analysisMetadataHolder.setProject(Project.copyOf(dto)); + analysisMetadataHolder.setBranch(new BranchImpl(branchName)); + return dto; + } + + private static class BranchImpl implements Branch { + private final String name; + + public BranchImpl(String name) { + this.name = name; + } + + @Override + public BranchType getType() { + return BranchType.LONG; + } + + @Override + public boolean isMain() { + return false; + } + + @Override + public java.util.Optional getName() { + return java.util.Optional.ofNullable(name); + } + + @Override + public boolean supportsCrossProjectCpd() { + return false; + } + + @Override + public String generateKey(ScannerReport.Component module, @Nullable ScannerReport.Component fileOrDir) { + String moduleKey = module.getKey(); + if (fileOrDir == null || isEmpty(fileOrDir.getPath())) { + return moduleKey; + } + return ComponentKeys.createEffectiveKey(moduleKey, trimToNull(fileOrDir.getPath())); + } + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ValidateProjectStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ValidateProjectStepTest.java index 7f91d63cfbd..aadb8186fe9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ValidateProjectStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ValidateProjectStepTest.java @@ -40,6 +40,8 @@ import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType; import org.sonar.server.computation.task.projectanalysis.analysis.Analysis; import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; +import org.sonar.server.computation.task.projectanalysis.analysis.Branch; +import org.sonar.server.computation.task.projectanalysis.component.MainBranchImpl; import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderRule; import org.sonar.server.computation.task.projectanalysis.component.Component; import org.sonar.server.computation.task.projectanalysis.component.ReportComponent; @@ -51,7 +53,7 @@ public class ValidateProjectStepTest { static long DEFAULT_ANALYSIS_TIME = 1433131200000L; // 2015-06-01 static final String PROJECT_KEY = "PROJECT_KEY"; static final String MODULE_KEY = "MODULE_KEY"; - static final String DEFAULT_BRANCH = "origin/master"; + static final Branch DEFAULT_BRANCH = new MainBranchImpl(null); @Rule public DbTester dbTester = DbTester.create(System2.INSTANCE); @@ -97,36 +99,6 @@ public class ValidateProjectStepTest { underTest.execute(); } - @Test - public void not_fail_on_valid_branch() { - analysisMetadataHolder.setBranch(DEFAULT_BRANCH); - reportReader.putComponent(ScannerReport.Component.newBuilder() - .setRef(1) - .setType(ComponentType.PROJECT) - .setKey(PROJECT_KEY) - .build()); - treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY + ":origin/master").build()); - - underTest.execute(); - } - - @Test - public void fail_on_invalid_branch() { - analysisMetadataHolder.setBranch("bran#ch"); - reportReader.putComponent(ScannerReport.Component.newBuilder() - .setRef(1) - .setType(ComponentType.PROJECT) - .setKey(PROJECT_KEY) - .build()); - treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY + ":bran#ch").build()); - - thrown.expect(MessageException.class); - thrown.expectMessage("Validation of project failed:\n" + - " o \"bran#ch\" is not a valid branch name. Allowed characters are alphanumeric, '-', '_', '.' and '/'."); - - underTest.execute(); - } - @Test public void fail_on_invalid_key() { String invalidProjectKey = "Project\\Key"; diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/VerifyBillingStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/VerifyBillingStepTest.java new file mode 100644 index 00000000000..5007d2d87c9 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/VerifyBillingStepTest.java @@ -0,0 +1,80 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.computation.task.projectanalysis.step; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.ArgumentCaptor; +import org.sonar.api.utils.MessageException; +import org.sonar.db.organization.OrganizationDto; +import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolderRule; +import org.sonar.server.computation.task.projectanalysis.analysis.Organization; +import org.sonar.server.organization.BillingValidations; +import org.sonar.server.organization.BillingValidations.BillingValidationsException; +import org.sonar.server.organization.BillingValidationsProxy; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto; + +public class VerifyBillingStepTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private OrganizationDto organization = newOrganizationDto(); + @Rule + public MutableAnalysisMetadataHolderRule analysisMetadata = new MutableAnalysisMetadataHolderRule() + .setOrganization(Organization.from(organization)); + + private BillingValidationsProxy validations = mock(BillingValidationsProxy.class); + + @Test + public void execute_fails_with_MessageException_when_organization_is_not_allowed_to_execute_analysis() { + doThrow(new BillingValidationsException("This organization cannot execute project analysis")) + .when(validations) + .checkOnProjectAnalysis(any(BillingValidations.Organization.class)); + + VerifyBillingStep underTest = new VerifyBillingStep(analysisMetadata, validations); + + expectedException.expect(MessageException.class); + expectedException.expectMessage("This organization cannot execute project analysis"); + + underTest.execute(); + + } + + @Test + public void execute_does_no_fail_when_organization_is_allowed_to_execute_analysis() { + ArgumentCaptor orgCaptor = ArgumentCaptor.forClass(BillingValidations.Organization.class); + + VerifyBillingStep underTest = new VerifyBillingStep(analysisMetadata, validations); + underTest.execute(); + + verify(validations).checkOnProjectAnalysis(orgCaptor.capture()); + BillingValidations.Organization calledOrg = orgCaptor.getValue(); + assertThat(calledOrg.getKey()).isEqualTo(organization.getKey()); + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ViewsPersistComponentsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ViewsPersistComponentsStepTest.java index 4cd7f3f54be..2c755957dba 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ViewsPersistComponentsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ViewsPersistComponentsStepTest.java @@ -37,6 +37,8 @@ import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; import org.sonar.db.organization.OrganizationDto; import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; +import org.sonar.server.computation.task.projectanalysis.component.BranchPersisterDelegate; +import org.sonar.server.computation.task.projectanalysis.component.MainBranchImpl; import org.sonar.server.computation.task.projectanalysis.component.MutableDbIdsRepositoryRule; import org.sonar.server.computation.task.projectanalysis.component.MutableDisabledComponentsHolder; import org.sonar.server.computation.task.projectanalysis.component.ProjectViewAttributes; @@ -93,6 +95,7 @@ public class ViewsPersistComponentsStepTest extends BaseStepTest { private ComponentDbTester componentDbTester = new ComponentDbTester(dbTester); private MutableDisabledComponentsHolder disabledComponentsHolder = mock(MutableDisabledComponentsHolder.class, RETURNS_DEEP_STUBS); private PersistComponentsStep underTest; + private BranchPersisterDelegate branchPersister; @Before public void setup() throws Exception { @@ -100,7 +103,8 @@ public class ViewsPersistComponentsStepTest extends BaseStepTest { when(system2.now()).thenReturn(now.getTime()); dbTester.organizations().insertForUuid(ORGANIZATION_UUID); - underTest = new PersistComponentsStep(dbClient, treeRootHolder, dbIdsRepository, system2, disabledComponentsHolder, analysisMetadataHolder); + analysisMetadataHolder.setBranch(new MainBranchImpl(null)); + underTest = new PersistComponentsStep(dbClient, treeRootHolder, dbIdsRepository, system2, disabledComponentsHolder, analysisMetadataHolder, branchPersister); } @Override diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookPostTaskTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookPostTaskTest.java index c630e803d16..044825700f1 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookPostTaskTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/webhook/WebhookPostTaskTest.java @@ -32,7 +32,6 @@ import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; import org.sonar.server.computation.task.projectanalysis.component.TestSettingsRepository; -import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; @@ -43,7 +42,6 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newCeTaskBuilder; import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newProjectBuilder; import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newScannerContextBuilder; -import static org.sonar.server.computation.task.projectanalysis.component.ReportComponent.DUMB_PROJECT; public class WebhookPostTaskTest { @@ -53,9 +51,6 @@ public class WebhookPostTaskTest { @Rule public LogTester logTester = new LogTester().setLevel(LoggerLevel.DEBUG); - @Rule - public TreeRootHolderRule rootHolder = new TreeRootHolderRule().setRoot(DUMB_PROJECT); - private final MapSettings settings = new MapSettings(); private final TestWebhookCaller caller = new TestWebhookCaller(); private final WebhookPayloadFactory payloadFactory = new TestWebhookPayloadFactory(); @@ -131,7 +126,7 @@ public class WebhookPostTaskTest { private void execute() { ConfigurationRepository settingsRepository = new TestSettingsRepository(settings.asConfig()); - WebhookPostTask task = new WebhookPostTask(rootHolder, settingsRepository, payloadFactory, caller, deliveryStorage); + WebhookPostTask task = new WebhookPostTask(settingsRepository, payloadFactory, caller, deliveryStorage); PostProjectAnalysisTaskTester.of(task) .at(new Date()) diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateServiceTest.java index 6b673dfadd5..2b7a933daad 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateServiceTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateServiceTest.java @@ -451,7 +451,7 @@ public class PermissionTemplateServiceTest { } @Test - public void would_user_have_scann_permission_with_empty_template() { + public void would_user_have_scan_permission_with_empty_template() { PermissionTemplateDto template = templateDb.insertTemplate(dbTester.getDefaultOrganization()); dbTester.organizations().setDefaultTemplates(template, null); @@ -459,7 +459,7 @@ public class PermissionTemplateServiceTest { } private void checkWouldUserHaveScanPermission(OrganizationDto organization, @Nullable Integer userId, boolean expectedResult) { - assertThat(underTest.wouldUserHaveScanPermissionWithDefaultTemplate(session, organization.getUuid(), userId, null, "PROJECT_KEY", Qualifiers.PROJECT)) + assertThat(underTest.wouldUserHaveScanPermissionWithDefaultTemplate(session, organization.getUuid(), userId, "PROJECT_KEY", Qualifiers.PROJECT)) .isEqualTo(expectedResult); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/ws/ProjectsWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/ws/ProjectsWsModuleTest.java index dd594cda099..49170c2652a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/project/ws/ProjectsWsModuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/project/ws/ProjectsWsModuleTest.java @@ -30,6 +30,6 @@ public class ProjectsWsModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new ProjectsWsModule().configure(container); - assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 14); + assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 15); } } diff --git a/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java b/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java index 599a898e273..562a5e7cf7a 100644 --- a/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java +++ b/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java @@ -19,9 +19,7 @@ */ package org.sonar.core.config; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import java.util.Arrays; +import java.util.ArrayList; import java.util.List; import org.sonar.api.CoreProperties; import org.sonar.api.PropertyType; @@ -29,6 +27,7 @@ import org.sonar.api.config.EmailSettings; import org.sonar.api.config.PropertyDefinition; import org.sonar.api.resources.Qualifiers; +import static java.util.Arrays.asList; import static org.sonar.api.PropertyType.BOOLEAN; import static org.sonar.api.database.DatabaseProperties.PROP_PASSWORD; @@ -54,7 +53,7 @@ public class CorePropertyDefinitions { } public static List all() { - List defs = Lists.newArrayList(); + List defs = new ArrayList<>(); defs.addAll(IssueExclusionProperties.all()); defs.addAll(ExclusionProperties.all()); defs.addAll(SecurityProperties.all()); @@ -63,8 +62,9 @@ public class CorePropertyDefinitions { defs.addAll(EmailSettings.definitions()); defs.addAll(WebhookProperties.all()); defs.addAll(TelemetryProperties.all()); + defs.addAll(ScannerProperties.all()); - defs.addAll(ImmutableList.of( + defs.addAll(asList( PropertyDefinition.builder(PROP_PASSWORD) .type(PropertyType.PASSWORD) .hidden() @@ -102,14 +102,6 @@ public class CorePropertyDefinitions { .category(CoreProperties.CATEGORY_GENERAL) .hidden() .build(), - PropertyDefinition.builder(CoreProperties.ANALYSIS_MODE) - .name("Analysis mode") - .type(PropertyType.SINGLE_SELECT_LIST) - .options(Arrays.asList(CoreProperties.ANALYSIS_MODE_ANALYSIS, CoreProperties.ANALYSIS_MODE_PREVIEW, CoreProperties.ANALYSIS_MODE_INCREMENTAL)) - .category(CoreProperties.CATEGORY_GENERAL) - .defaultValue(CoreProperties.ANALYSIS_MODE_ANALYSIS) - .hidden() - .build(), PropertyDefinition.builder(CoreProperties.PREVIEW_INCLUDE_PLUGINS) .name("Plugins accepted for Preview mode") .description("List of plugin keys. Those plugins will be used during preview analyses.") @@ -148,20 +140,6 @@ public class CorePropertyDefinitions { .defaultValue(String.valueOf(false)) .hidden() .build(), - PropertyDefinition.builder(CoreProperties.SCM_DISABLED_KEY) - .name("Disable the SCM Sensor") - .description("Disable the retrieval of blame information from Source Control Manager") - .category(CoreProperties.CATEGORY_SCM) - .type(BOOLEAN) - .onQualifiers(Qualifiers.PROJECT) - .defaultValue(String.valueOf(false)) - .build(), - PropertyDefinition.builder(CoreProperties.SCM_PROVIDER_KEY) - .name("Key of the SCM provider for this project") - .description("Force the provider to be used to get SCM information for this project. By default auto-detection is done. Example: svn, git.") - .category(CoreProperties.CATEGORY_SCM) - .onlyOnQualifiers(Qualifiers.PROJECT) - .build(), PropertyDefinition.builder(DISABLE_NOTIFICATION_ON_BUILT_IN_QPROFILES) .name("Avoid quality profiles notification") .description("Avoid sending email notification on each update of built-in quality profiles to quality profile administrators.") diff --git a/sonar-core/src/main/java/org/sonar/core/config/PurgeProperties.java b/sonar-core/src/main/java/org/sonar/core/config/PurgeProperties.java index d56cbe687f0..89a210879e1 100644 --- a/sonar-core/src/main/java/org/sonar/core/config/PurgeProperties.java +++ b/sonar-core/src/main/java/org/sonar/core/config/PurgeProperties.java @@ -19,20 +19,21 @@ */ package org.sonar.core.config; -import java.util.Arrays; import java.util.List; import org.sonar.api.CoreProperties; import org.sonar.api.PropertyType; import org.sonar.api.config.PropertyDefinition; import org.sonar.api.resources.Qualifiers; +import static java.util.Arrays.asList; + public final class PurgeProperties { private PurgeProperties() { } public static List all() { - return Arrays.asList( + return asList( PropertyDefinition.builder(PurgeConstants.PROPERTY_CLEAN_DIRECTORY) .defaultValue("true") .name("Clean directory/package history") diff --git a/sonar-core/src/main/java/org/sonar/core/config/ScannerProperties.java b/sonar-core/src/main/java/org/sonar/core/config/ScannerProperties.java new file mode 100644 index 00000000000..e7abb6654c0 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/config/ScannerProperties.java @@ -0,0 +1,76 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.core.config; + +import java.util.List; +import org.sonar.api.CoreProperties; +import org.sonar.api.PropertyType; +import org.sonar.api.config.PropertyDefinition; +import org.sonar.api.resources.Qualifiers; + +import static java.util.Arrays.asList; +import static org.sonar.api.PropertyType.BOOLEAN; + +public class ScannerProperties { + + public static final String BRANCH_NAME = "sonar.branch.name"; + public static final String ORGANIZATION = "sonar.organization"; + + private ScannerProperties() { + // only static stuff + } + + public static List all() { + return asList( + PropertyDefinition.builder(CoreProperties.ANALYSIS_MODE) + .name("Analysis mode") + .type(PropertyType.SINGLE_SELECT_LIST) + .options(asList(CoreProperties.ANALYSIS_MODE_ANALYSIS, CoreProperties.ANALYSIS_MODE_PREVIEW, CoreProperties.ANALYSIS_MODE_INCREMENTAL)) + .category(CoreProperties.CATEGORY_GENERAL) + .defaultValue(CoreProperties.ANALYSIS_MODE_ANALYSIS) + .hidden() + .build(), + PropertyDefinition.builder(CoreProperties.SCM_DISABLED_KEY) + .name("Disable the SCM Sensor") + .description("Disable the retrieval of blame information from Source Control Manager") + .category(CoreProperties.CATEGORY_SCM) + .type(BOOLEAN) + .onQualifiers(Qualifiers.PROJECT) + .defaultValue(String.valueOf(false)) + .build(), + PropertyDefinition.builder(CoreProperties.SCM_PROVIDER_KEY) + .name("Key of the SCM provider for this project") + .description("Force the provider to be used to get SCM information for this project. By default auto-detection is done. Example: svn, git.") + .category(CoreProperties.CATEGORY_SCM) + .onlyOnQualifiers(Qualifiers.PROJECT) + .build(), + PropertyDefinition.builder(ORGANIZATION) + .name("Organization key") + .description("Key of the organization that contains the project being analyzed. If unset, then the organization marked as default is used.") + .hidden() + .build(), + PropertyDefinition.builder(BRANCH_NAME) + .name("Optional name of SCM branch") + .description("TODO") + .hidden() + .build() + ); + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/config/WebhookProperties.java b/sonar-core/src/main/java/org/sonar/core/config/WebhookProperties.java index 5f79551fd1e..91fb4c141e8 100644 --- a/sonar-core/src/main/java/org/sonar/core/config/WebhookProperties.java +++ b/sonar-core/src/main/java/org/sonar/core/config/WebhookProperties.java @@ -19,13 +19,14 @@ */ package org.sonar.core.config; -import com.google.common.collect.ImmutableList; import java.util.List; import org.sonar.api.PropertyType; import org.sonar.api.config.PropertyDefinition; import org.sonar.api.config.PropertyFieldDefinition; import org.sonar.api.resources.Qualifiers; +import static java.util.Arrays.asList; + public class WebhookProperties { public static final String GLOBAL_KEY = "sonar.webhooks.global"; @@ -56,7 +57,7 @@ public class WebhookProperties { } static List all() { - return ImmutableList.of( + return asList( PropertyDefinition.builder(GLOBAL_KEY) .category(CATEGORY) .name("Webhooks") diff --git a/sonar-core/src/main/java/org/sonar/core/platform/PluginLoader.java b/sonar-core/src/main/java/org/sonar/core/platform/PluginLoader.java index 2ba2427e8d6..b084ba686b0 100644 --- a/sonar-core/src/main/java/org/sonar/core/platform/PluginLoader.java +++ b/sonar-core/src/main/java/org/sonar/core/platform/PluginLoader.java @@ -55,7 +55,7 @@ public class PluginLoader { * Defines the base keys (defined by {@link #basePluginKey(PluginInfo, Map)}) of the plugins which are allowed to * run a full server extensions. */ - private static final Set PRIVILEGED_PLUGINS_BASE_KEYS = ImmutableSet.of("views", "devcockpit", "governance", "billing", "developer", "incremental"); + private static final Set PRIVILEGED_PLUGINS_BASE_KEYS = ImmutableSet.of("views", "devcockpit", "governance", "billing", "developer", "incremental", "branch"); public static final Version COMPATIBILITY_MODE_MAX_VERSION = Version.create("5.2"); diff --git a/sonar-core/src/test/java/org/sonar/core/config/CorePropertyDefinitionsTest.java b/sonar-core/src/test/java/org/sonar/core/config/CorePropertyDefinitionsTest.java index 22b04b1f5e4..897227b77f6 100644 --- a/sonar-core/src/test/java/org/sonar/core/config/CorePropertyDefinitionsTest.java +++ b/sonar-core/src/test/java/org/sonar/core/config/CorePropertyDefinitionsTest.java @@ -33,7 +33,7 @@ public class CorePropertyDefinitionsTest { @Test public void all() { List defs = CorePropertyDefinitions.all(); - assertThat(defs).hasSize(61); + assertThat(defs).hasSize(63); } @Test @@ -44,4 +44,12 @@ public class CorePropertyDefinitionsTest { assertThat(prop.get().type()).isEqualTo(PropertyType.PASSWORD); } + @Test + public void all_includes_scanner_properties() { + List defs = CorePropertyDefinitions.all(); + + assertThat(defs.stream() + .filter(def -> def.key().equals(ScannerProperties.BRANCH_NAME)) + .findFirst()).isPresent(); + } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java b/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java index 5400fcb4411..a93bdd35381 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java @@ -126,11 +126,6 @@ public interface CoreProperties { String PROJECT_BRANCH_PROPERTY = "sonar.branch"; String PROJECT_VERSION_PROPERTY = "sonar.projectVersion"; - /** - * @since 6.3 - */ - String PROJECT_ORGANIZATION_PROPERTY = "sonar.organization"; - /** * @since 2.6 */ diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/TaskResult.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/TaskResult.java index 41786c272da..680876ef33d 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/TaskResult.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/TaskResult.java @@ -77,14 +77,14 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver if (!container.getComponentByType(AnalysisMode.class).isIssues()) { Metadata readMetadata = getReportReader().readMetadata(); int rootComponentRef = readMetadata.getRootComponentRef(); - storeReportComponents(rootComponentRef, null, readMetadata.getBranch()); + storeReportComponents(rootComponentRef, null); } storeFs(container); } - private void storeReportComponents(int componentRef, String parentModuleKey, String branch) { + private void storeReportComponents(int componentRef, String parentModuleKey) { Component component = getReportReader().readComponent(componentRef); if (isNotEmpty(component.getKey())) { reportComponents.put(component.getKey(), component); @@ -92,7 +92,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver reportComponents.put(parentModuleKey + ":" + component.getPath(), component); } for (int childId : component.getChildRefList()) { - storeReportComponents(childId, isNotEmpty(component.getKey()) ? component.getKey() : parentModuleKey, branch); + storeReportComponents(childId, isNotEmpty(component.getKey()) ? component.getKey() : parentModuleKey); } } @@ -174,7 +174,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver * @param lineOffset 0-based offset in file */ public List highlightingTypeFor(InputFile file, int line, int lineOffset) { - int ref = reportComponents.get(((DefaultInputFile) file).key()).getRef(); + int ref = reportComponents.get(file.key()).getRef(); if (!reader.hasSyntaxHighlighting(ref)) { return Collections.emptyList(); } @@ -205,7 +205,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver */ @CheckForNull public List symbolReferencesFor(InputFile file, int symbolStartLine, int symbolStartLineOffset) { - int ref = reportComponents.get(((DefaultInputFile) file).key()).getRef(); + int ref = reportComponents.get(file.key()).getRef(); try (CloseableIterator symbols = getReportReader().readComponentSymbols(ref)) { while (symbols.hasNext()) { Symbol symbol = symbols.next(); @@ -219,7 +219,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver public List duplicationsFor(InputFile file) { List result = new ArrayList<>(); - int ref = reportComponents.get(((DefaultInputFile) file).key()).getRef(); + int ref = reportComponents.get(file.key()).getRef(); try (CloseableIterator it = getReportReader().readComponentDuplications(ref)) { while (it.hasNext()) { result.add(it.next()); @@ -232,7 +232,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver public List duplicationBlocksFor(InputFile file) { List result = new ArrayList<>(); - int ref = reportComponents.get(((DefaultInputFile) file).key()).getRef(); + int ref = reportComponents.get(file.key()).getRef(); try (CloseableIterator it = getReportReader().readCpdTextBlocks(ref)) { while (it.hasNext()) { result.add(it.next()); @@ -245,7 +245,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver @CheckForNull public ScannerReport.LineCoverage coverageFor(InputFile file, int line) { - int ref = reportComponents.get(((DefaultInputFile) file).key()).getRef(); + int ref = reportComponents.get(file.key()).getRef(); try (CloseableIterator it = getReportReader().readComponentCoverage(ref)) { while (it.hasNext()) { ScannerReport.LineCoverage coverage = it.next(); @@ -260,7 +260,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver } public ScannerReport.Test firstTestExecutionForName(InputFile testFile, String testName) { - int ref = reportComponents.get(((DefaultInputFile) testFile).key()).getRef(); + int ref = reportComponents.get(testFile.key()).getRef(); try (InputStream inputStream = FileUtils.openInputStream(getReportReader().readTests(ref))) { ScannerReport.Test test = ScannerReport.Test.parser().parseDelimitedFrom(inputStream); while (test != null) { @@ -276,7 +276,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver } public ScannerReport.CoverageDetail coveragePerTestFor(InputFile testFile, String testName) { - int ref = reportComponents.get(((DefaultInputFile) testFile).key()).getRef(); + int ref = reportComponents.get(testFile.key()).getRef(); try (InputStream inputStream = FileUtils.openInputStream(getReportReader().readCoverageDetails(ref))) { ScannerReport.CoverageDetail details = ScannerReport.CoverageDetail.parser().parseDelimitedFrom(inputStream); while (details != null) { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java index 15f0a0cfcf8..258ac5ada08 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java @@ -20,8 +20,8 @@ package org.sonar.scanner.report; import java.util.Map.Entry; -import org.sonar.api.CoreProperties; import org.sonar.api.batch.AnalysisMode; +import java.util.Optional; import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.InputModuleHierarchy; @@ -35,6 +35,9 @@ import org.sonar.scanner.protocol.output.ScannerReportWriter; import org.sonar.scanner.rule.ModuleQProfiles; import org.sonar.scanner.rule.QProfile; +import static org.sonar.core.config.ScannerProperties.BRANCH_NAME; +import static org.sonar.core.config.ScannerProperties.ORGANIZATION; + public class MetadataPublisher implements ReportPublisherStep { private final Configuration settings; @@ -68,12 +71,10 @@ public class MetadataPublisher implements ReportPublisherStep { .setRootComponentRef(rootProject.batchId()) .setIncremental(mode.isIncremental()); - settings.get(CoreProperties.PROJECT_ORGANIZATION_PROPERTY).ifPresent(builder::setOrganizationKey); + settings.get(ORGANIZATION).ifPresent(builder::setOrganizationKey); + settings.get(BRANCH_NAME).ifPresent(builder::setBranchName); + Optional.ofNullable(rootDef.getBranch()).ifPresent(builder::setDeprecatedBranch); - String branch = rootDef.getBranch(); - if (branch != null) { - builder.setBranch(branch); - } for (QProfile qp : qProfiles.findAll()) { builder.getMutableQprofilesPerLanguage().put(qp.getLanguage(), ScannerReport.Metadata.QProfile.newBuilder() .setKey(qp.getKey()) diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java index 0815ffdf81d..f58536c2654 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java @@ -35,7 +35,6 @@ import javax.annotation.Nullable; import okhttp3.HttpUrl; import org.apache.commons.io.FileUtils; import org.picocontainer.Startable; -import org.sonar.api.CoreProperties; import org.sonar.api.batch.ScannerSide; import org.sonar.api.batch.fs.internal.InputModuleHierarchy; import org.sonar.api.config.Configuration; @@ -54,6 +53,7 @@ import org.sonarqube.ws.client.HttpException; import org.sonarqube.ws.client.PostRequest; import org.sonarqube.ws.client.WsResponse; +import static org.sonar.core.config.ScannerProperties.ORGANIZATION; import static org.sonar.core.util.FileUtils.deleteQuietly; @ScannerSide @@ -167,7 +167,7 @@ public class ReportPublisher implements Startable { PostRequest.Part filePart = new PostRequest.Part(MediaTypes.ZIP, report); PostRequest post = new PostRequest("api/ce/submit") .setMediaType(MediaTypes.PROTOBUF) - .setParam("organization", settings.get(CoreProperties.PROJECT_ORGANIZATION_PROPERTY).orElse(null)) + .setParam("organization", settings.get(ORGANIZATION).orElse(null)) .setParam("projectKey", moduleHierarchy.root().key()) .setParam("projectName", moduleHierarchy.root().getOriginalName()) .setParam("projectBranch", moduleHierarchy.root().getBranch()) @@ -204,7 +204,7 @@ public class ReportPublisher implements Startable { Map metadata = new LinkedHashMap<>(); String effectiveKey = moduleHierarchy.root().getKeyWithBranch(); - settings.get(CoreProperties.PROJECT_ORGANIZATION_PROPERTY).ifPresent(org -> metadata.put("organization", org)); + settings.get(ORGANIZATION).ifPresent(org -> metadata.put("organization", org)); metadata.put("projectKey", effectiveKey); metadata.put("serverUrl", publicUrl); metadata.put("serverVersion", server.getVersion()); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultQualityProfileLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultQualityProfileLoader.java index eb86e53237a..779174757d4 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultQualityProfileLoader.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultQualityProfileLoader.java @@ -29,7 +29,6 @@ import java.util.Optional; import java.util.function.BinaryOperator; import javax.annotation.Nullable; import org.apache.commons.io.IOUtils; -import org.sonar.api.CoreProperties; import org.sonar.api.config.Configuration; import org.sonar.api.utils.MessageException; import org.sonar.scanner.bootstrap.ScannerWsClient; @@ -39,6 +38,7 @@ import org.sonarqube.ws.client.GetRequest; import static java.util.function.Function.identity; import static java.util.stream.Collectors.toMap; +import static org.sonar.core.config.ScannerProperties.ORGANIZATION; import static org.sonar.scanner.util.ScannerUtils.encodeForUrl; public class DefaultQualityProfileLoader implements QualityProfileLoader { @@ -82,7 +82,7 @@ public class DefaultQualityProfileLoader implements QualityProfileLoader { } private Optional getOrganizationKey() { - return settings.get(CoreProperties.PROJECT_ORGANIZATION_PROPERTY); + return settings.get(ORGANIZATION); } private Map call(String url) { diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/branch/BranchMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/branch/BranchMediumTest.java index 8761acc1e5c..88020f9eb5d 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/branch/BranchMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/branch/BranchMediumTest.java @@ -95,7 +95,7 @@ public class BranchMediumTest { DefaultInputFile inputfile = (DefaultInputFile) result.inputFile("src/sample.xoo"); assertThat(result.getReportReader().readComponent(inputfile.batchId()).getPath()).isEqualTo("src/sample.xoo"); - assertThat(result.getReportReader().readMetadata().getBranch()).isEqualTo("branch"); + assertThat(result.getReportReader().readMetadata().getDeprecatedBranch()).isEqualTo("branch"); result = tester.newTask() .properties(ImmutableMap.builder() @@ -134,7 +134,7 @@ public class BranchMediumTest { // no branch in InputModule's key or in report assertThat(result.getReportComponent("com.foo.project:moduleA").getKey()).isEqualTo("com.foo.project:moduleA"); - assertThat(result.getReportReader().readMetadata().getBranch()).isEqualTo("branch"); + assertThat(result.getReportReader().readMetadata().getDeprecatedBranch()).isEqualTo("branch"); result = tester.newTask() .properties(ImmutableMap.builder() diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java index a949364d429..3a4051ece54 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java @@ -34,6 +34,7 @@ import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.InputModuleHierarchy; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; import org.sonar.api.config.internal.MapSettings; +import org.sonar.core.config.ScannerProperties; import org.sonar.scanner.ProjectAnalysisInfo; import org.sonar.scanner.bootstrap.ScannerPlugin; import org.sonar.scanner.bootstrap.ScannerPluginRepository; @@ -141,13 +142,13 @@ public class MetadataPublisherTest { ScannerReport.Metadata metadata = reader.readMetadata(); assertThat(metadata.getAnalysisDate()).isEqualTo(1234567L); assertThat(metadata.getProjectKey()).isEqualTo("foo"); - assertThat(metadata.getBranch()).isEqualTo("myBranch"); + assertThat(metadata.getDeprecatedBranch()).isEqualTo("myBranch"); assertThat(metadata.getCrossProjectDuplicationActivated()).isFalse(); } @Test public void write_project_organization() throws Exception { - settings.setProperty(CoreProperties.PROJECT_ORGANIZATION_PROPERTY, "SonarSource"); + settings.setProperty(ScannerProperties.ORGANIZATION, "SonarSource"); File outputDir = temp.newFolder(); ScannerReportWriter writer = new ScannerReportWriter(outputDir); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java index ae65b6d01b7..9138d06f8c4 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java @@ -32,7 +32,6 @@ import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; -import org.sonar.api.CoreProperties; import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.InputModuleHierarchy; @@ -44,6 +43,7 @@ import org.sonar.api.utils.TempFolder; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; import org.sonar.core.config.CorePropertyDefinitions; +import org.sonar.core.config.ScannerProperties; import org.sonar.scanner.analysis.DefaultAnalysisMode; import org.sonar.scanner.bootstrap.ScannerWsClient; import org.sonarqube.ws.WsCe; @@ -91,7 +91,7 @@ public class ReportPublisherTest { public void log_and_dump_information_about_report_uploading() throws IOException { ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class), new ReportPublisherStep[0]); - settings.setProperty(CoreProperties.PROJECT_ORGANIZATION_PROPERTY, "MyOrg"); + settings.setProperty(ScannerProperties.ORGANIZATION, "MyOrg"); underTest.logSuccess("TASK-123"); @@ -202,7 +202,7 @@ public class ReportPublisherTest { ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class), new ReportPublisherStep[0]); - settings.setProperty(CoreProperties.PROJECT_ORGANIZATION_PROPERTY, "MyOrg"); + settings.setProperty(ScannerProperties.ORGANIZATION, "MyOrg"); WsResponse response = mock(WsResponse.class); @@ -232,7 +232,7 @@ public class ReportPublisherTest { new ReportPublisherStep[0]); when(mode.isIncremental()).thenReturn(true); - settings.setProperty(CoreProperties.PROJECT_ORGANIZATION_PROPERTY, "MyOrg"); + settings.setProperty(ScannerProperties.ORGANIZATION, "MyOrg"); WsResponse response = mock(WsResponse.class); diff --git a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/viewer/ScannerReportViewerApp.java b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/viewer/ScannerReportViewerApp.java index ed5accc8d00..cc200fe05bc 100644 --- a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/viewer/ScannerReportViewerApp.java +++ b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/viewer/ScannerReportViewerApp.java @@ -239,7 +239,7 @@ public class ScannerReportViewerApp { } private void updateTitle() { - frame.setTitle(metadata.getProjectKey() + (StringUtils.isNotEmpty(metadata.getBranch()) ? (" (" + metadata.getBranch() + ")") : "") + " " + frame.setTitle(metadata.getProjectKey() + (StringUtils.isNotEmpty(metadata.getBranchName()) ? (" (" + metadata.getBranchName() + ")") : "") + " " + sdf.format(new Date(metadata.getAnalysisDate()))); } diff --git a/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto b/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto index 4cbecc33241..5affc439446 100644 --- a/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto +++ b/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto @@ -33,12 +33,14 @@ message Metadata { string organization_key = 2; // TODO should we keep this project_key here or not ? Because it's a duplication of Component.key string project_key = 3; - string branch = 4; + // maps the property sonar.branch + string deprecated_branch = 4; int32 root_component_ref = 5; bool cross_project_duplication_activated = 6; map qprofiles_per_language = 7; map plugins_by_key = 8; bool incremental = 9; + string branch_name = 10; message QProfile { string key = 1; diff --git a/sonar-ws/src/main/protobuf/ws-projects.proto b/sonar-ws/src/main/protobuf/ws-projects.proto index 8668ffc355a..069db2f37f7 100644 --- a/sonar-ws/src/main/protobuf/ws-projects.proto +++ b/sonar-ws/src/main/protobuf/ws-projects.proto @@ -84,3 +84,24 @@ message BulkUpdateKeyWsResponse { optional bool duplicate = 3; } } + +// WS api/projects/branches +message BranchesWsResponse { + repeated Branch branches = 1; + + message Branch { + optional string name = 1; + optional bool isMain = 2; + optional BranchType type = 3; + } + + enum BranchType { + // Zero is required in order to not get MAINTAINABILITY as default value + // See http://androiddevblog.com/protocol-buffers-pitfall-adding-enum-values/ + UNKNOWN = 0; + + LONG = 1; + SHORT = 2; + } + +} diff --git a/tests/projects/shared/xoo-multi-module-sample-without-project-name-version/.scannerwork/.sonar_lock b/tests/projects/shared/xoo-multi-module-sample-without-project-name-version/.scannerwork/.sonar_lock new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/projects/shared/xoo-multi-module-sample-without-project-name-version/.scannerwork/report-task.txt b/tests/projects/shared/xoo-multi-module-sample-without-project-name-version/.scannerwork/report-task.txt new file mode 100644 index 00000000000..abc19fd381e --- /dev/null +++ b/tests/projects/shared/xoo-multi-module-sample-without-project-name-version/.scannerwork/report-task.txt @@ -0,0 +1,6 @@ +projectKey=com.sonarsource.it.samples:multi-modules-sample +serverUrl=http://localhost:9000 +serverVersion=6.6-SNAPSHOT +dashboardUrl=http://localhost:9000/dashboard/index/com.sonarsource.it.samples:multi-modules-sample +ceTaskId=AV2ZBK0ixJXLis3IozUo +ceTaskUrl=http://localhost:9000/api/ce/task?id=AV2ZBK0ixJXLis3IozUo -- 2.39.5