From 36e9f01ad563aaeaae36dc6efc69e724f8c039c1 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Mon, 22 May 2023 15:21:06 -0500 Subject: [PATCH] SONAR-18856 Refactor properties and related web services --- .../analysis/ProjectConfigurationFactory.java | 6 +- .../ConfigurationRepositoryImpl.java | 5 +- .../ProjectConfigurationFactoryTest.java | 11 ++- .../ConfigurationRepositoryTest.java | 9 +-- .../sonar/db/component/ComponentDaoIT.java | 49 +------------ .../org/sonar/db/project/ProjectDaoIT.java | 43 ++++++++++++ .../org/sonar/db/component/ComponentDao.java | 11 --- .../sonar/db/component/ComponentMapper.java | 2 - .../java/org/sonar/db/project/ProjectDao.java | 11 +-- .../org/sonar/db/project/ProjectMapper.java | 3 + .../sonar/db/component/ComponentMapper.xml | 16 ----- .../org/sonar/db/project/ProjectMapper.xml | 17 ++++- .../sonar/db/property/PropertyTesting.java | 12 ---- .../component/index/ComponentIndexerIT.java | 1 - .../server/component/index/ComponentDoc.java | 17 ----- .../index/ComponentIndexDefinition.java | 2 - .../component/index/ComponentIndexer.java | 38 +++++----- .../sonar/server/favorite/ws/AddActionIT.java | 2 +- .../server/favorite/ws/RemoveActionIT.java | 6 +- .../setting/ws/ListDefinitionsActionIT.java | 12 ++-- .../server/setting/ws/ResetActionIT.java | 5 +- .../sonar/server/setting/ws/SetActionIT.java | 6 +- .../server/setting/ws/ValuesActionIT.java | 4 +- .../component/ws/SuggestionsAction.java | 2 +- .../sonar/server/favorite/FavoriteFinder.java | 4 +- .../sonar/server/favorite/ws/AddAction.java | 8 +-- .../server/favorite/ws/RemoveAction.java | 4 +- .../setting/ws/ListDefinitionsAction.java | 31 ++++---- .../sonar/server/setting/ws/ResetAction.java | 53 ++------------ .../sonar/server/setting/ws/SetAction.java | 6 +- .../server/setting/ws/SettingValidations.java | 2 +- .../server/setting/ws/SettingsWsSupport.java | 9 +-- .../sonar/server/setting/ws/ValuesAction.java | 70 +++++++------------ .../setting/ws/SettingsWsSupportTest.java | 10 +-- .../src/main/protobuf/ws-components.proto | 9 +-- 35 files changed, 173 insertions(+), 323 deletions(-) diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactory.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactory.java index cfe3b7fc4ad..fc8ea893049 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactory.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactory.java @@ -38,13 +38,9 @@ public class ProjectConfigurationFactory { this.dbClient = dbClient; } - public Configuration newProjectConfiguration(String projectUuid, String branchUuid) { + public Configuration newProjectConfiguration(String projectUuid) { Settings projectSettings = new ChildSettings(globalSettings); addSettings(projectSettings, projectUuid); - if (!projectUuid.equals(branchUuid)) { - // TODO not supported? - addSettings(projectSettings, branchUuid); - } return new ConfigurationBridge(projectSettings); } diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ConfigurationRepositoryImpl.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ConfigurationRepositoryImpl.java index 8257bb7950d..3181bf6f1eb 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ConfigurationRepositoryImpl.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ConfigurationRepositoryImpl.java @@ -32,11 +32,10 @@ public class ConfigurationRepositoryImpl implements ConfigurationRepository { private final Supplier configuration; - public ConfigurationRepositoryImpl(TreeRootHolder treeRootHolder, AnalysisMetadataHolder analysisMetadataHolder, ProjectConfigurationFactory f) { + public ConfigurationRepositoryImpl(AnalysisMetadataHolder analysisMetadataHolder, ProjectConfigurationFactory f) { this.configuration = Suppliers.memoize(() -> { - String branchUuid = treeRootHolder.getRoot().getUuid(); String projectUuid = analysisMetadataHolder.getProject().getUuid(); - return f.newProjectConfiguration(projectUuid, branchUuid); + return f.newProjectConfiguration(projectUuid); }); } diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactoryTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactoryTest.java index c56459bc94f..c70c6545bcb 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactoryTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactoryTest.java @@ -24,7 +24,6 @@ import org.junit.Test; import org.sonar.api.config.Configuration; import org.sonar.api.config.internal.MapSettings; import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; import org.sonar.db.project.ProjectDto; import static org.assertj.core.api.Assertions.assertThat; @@ -34,13 +33,13 @@ public class ProjectConfigurationFactoryTest { @Rule public DbTester db = DbTester.create(); - private MapSettings settings = new MapSettings(); - private ProjectConfigurationFactory underTest = new ProjectConfigurationFactory(settings, db.getDbClient()); + private final MapSettings settings = new MapSettings(); + private final ProjectConfigurationFactory underTest = new ProjectConfigurationFactory(settings, db.getDbClient()); @Test public void return_global_settings() { settings.setProperty("key", "value"); - Configuration config = underTest.newProjectConfiguration("unknown", "unknown"); + Configuration config = underTest.newProjectConfiguration("unknown"); assertThat(config.get("key")).hasValue("value"); } @@ -53,7 +52,7 @@ public class ProjectConfigurationFactoryTest { newComponentPropertyDto(project).setKey("2").setValue("val2"), newComponentPropertyDto(project).setKey("3").setValue("val3")); - Configuration config = underTest.newProjectConfiguration(project.getUuid(), project.getUuid()); + Configuration config = underTest.newProjectConfiguration(project.getUuid()); assertThat(config.get("1")).hasValue("val1"); assertThat(config.get("2")).hasValue("val2"); @@ -67,7 +66,7 @@ public class ProjectConfigurationFactoryTest { db.properties().insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("key").setValue("value2")); - Configuration projectConfig = underTest.newProjectConfiguration(project.getUuid(), project.getUuid()); + Configuration projectConfig = underTest.newProjectConfiguration(project.getUuid()); assertThat(projectConfig.get("key")).hasValue("value2"); } diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ConfigurationRepositoryTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ConfigurationRepositoryTest.java index a8230f38e62..a13d8e656ac 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ConfigurationRepositoryTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ConfigurationRepositoryTest.java @@ -26,15 +26,12 @@ import org.sonar.api.config.Configuration; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.utils.System2; import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule; -import org.sonar.ce.task.projectanalysis.analysis.Branch; import org.sonar.ce.task.projectanalysis.analysis.ProjectConfigurationFactory; import org.sonar.db.DbClient; import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; import org.sonar.db.property.PropertyDto; import org.sonar.server.project.Project; -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -44,8 +41,6 @@ public class ConfigurationRepositoryTest { @Rule public final DbTester db = DbTester.create(System2.INSTANCE); @Rule - public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); - @Rule public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule(); private final DbClient dbClient = db.getDbClient(); @@ -54,13 +49,11 @@ public class ConfigurationRepositoryTest { private final Component root = mock(Component.class); private ConfigurationRepository underTest; - @Before public void setUp() { analysisMetadataHolder.setProject(project); when(root.getUuid()).thenReturn(project.getUuid()); - treeRootHolder.setRoot(root); - underTest = new ConfigurationRepositoryImpl(treeRootHolder, analysisMetadataHolder, new ProjectConfigurationFactory(globalSettings, dbClient)); + underTest = new ConfigurationRepositoryImpl(analysisMetadataHolder, new ProjectConfigurationFactory(globalSettings, dbClient)); } @Test diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/component/ComponentDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/component/ComponentDaoIT.java index a51ca2af3b1..beb63a96a19 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/component/ComponentDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/component/ComponentDaoIT.java @@ -22,7 +22,6 @@ package org.sonar.db.component; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; @@ -36,8 +35,6 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; -import javax.annotation.Nullable; -import org.assertj.core.api.ListAssert; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -322,7 +319,7 @@ public class ComponentDaoIT { assertThat(results) .extracting(ComponentDto::uuid, ComponentDto::getKey) - .isEmpty(); + .isEmpty(); } @Test @@ -1066,50 +1063,6 @@ public class ComponentDaoIT { removedFile.uuid()); } - @Test - public void selectForIndexing_all() { - assertSelectForIndexing(null) - .doesNotContain("DIS7") - .doesNotContain("COPY8") // copied projects - .doesNotContain("U2", "U6")// modules - .doesNotContain("U3")// dir - .doesNotContain("U4")// file - .containsExactlyInAnyOrder("U1", "U5", "VW1"); - } - - @Test - public void selectForIndexing_project() { - assertSelectForIndexing("U1") - .doesNotContain("DIS7") - .doesNotContain("COPY8") // copied projects - .doesNotContain("U6") // other projects - .doesNotContain("VW1") // view - .doesNotContain("U2", "U6")// modules - .doesNotContain("U3")// dir - .doesNotContain("U4")// file - .containsExactlyInAnyOrder("U1"); - } - - private ListAssert assertSelectForIndexing(@Nullable String projectUuid) { - ComponentDto project = db.components().insertPrivateProject("U1").getMainBranchComponent(); - ComponentDto removedProject = db.components().insertPrivateProject(p -> p.setEnabled(false)).getMainBranchComponent(); - ComponentDto directory = db.components().insertComponent(newDirectory(project, "U3", "src")); - ComponentDto removedDirectory = db.components().insertComponent(newDirectory(project, "src2").setEnabled(false)); - ComponentDto file = db.components().insertComponent(newFileDto(project, directory, "U4")); - ComponentDto removedFile = db.components().insertComponent(newFileDto(project, directory).setEnabled(false)); - - ComponentDto view = db.components().insertPublicPortfolio("VW1", p -> { - }); - db.components().insertComponent(newProjectCopy("COPY8", project, view)); - - ComponentDto project2 = db.components().insertPrivateProject("U5").getMainBranchComponent(); - - List components = new ArrayList<>(); - underTest.scrollForIndexing(dbSession, projectUuid, - context -> components.add(context.getResultObject())); - return (ListAssert) assertThat(components).extracting(ComponentDto::uuid); - } - @Test public void update() { db.components().insertPrivateProject("U1").getMainBranchComponent(); diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java index 78dd3c197bd..219c9f4c13e 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java @@ -24,6 +24,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Optional; import java.util.Set; @@ -31,6 +32,7 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.IntStream; import javax.annotation.Nullable; +import org.apache.ibatis.session.ResultHandler; import org.assertj.core.api.Assertions; import org.assertj.core.groups.Tuple; import org.junit.Rule; @@ -406,6 +408,47 @@ public class ProjectDaoIT { assertThat(projectDao.selectEntityByKey(db.getSession(), "unknown")).isEmpty(); } + @Test + public void scrollEntitiesForIndexing_shouldReturnAllEntities() { + ProjectData application = db.components().insertPrivateApplication(); + ProjectData project = db.components().insertPrivateProject(); + PortfolioDto portfolio = db.components().insertPrivatePortfolioDto(); + + List result = new LinkedList<>(); + ResultHandler handler = resultContext -> result.add(resultContext.getResultObject()); + projectDao.scrollEntitiesForIndexing(db.getSession(), null, handler); + + assertThat(result).extracting(EntityDto::getUuid) + .containsOnly(project.projectUuid(), application.projectUuid(), portfolio.getUuid()); + } + + @Test + public void scrollEntitiesForIndexing_whenEntityUuidSpecified_shouldReturnSpecificEntity() { + ProjectData application = db.components().insertPrivateApplication(); + ProjectData project = db.components().insertPrivateProject(); + PortfolioDto portfolio = db.components().insertPrivatePortfolioDto(); + + List result = new LinkedList<>(); + ResultHandler handler = resultContext -> result.add(resultContext.getResultObject()); + projectDao.scrollEntitiesForIndexing(db.getSession(), project.projectUuid(), handler); + + assertThat(result).extracting(EntityDto::getUuid) + .containsOnly(project.projectUuid()); + } + + @Test + public void scrollEntitiesForIndexing_whenNonExistingUuidSpecified_shouldReturnEmpty() { + ProjectData application = db.components().insertPrivateApplication(); + ProjectData project = db.components().insertPrivateProject(); + PortfolioDto portfolio = db.components().insertPrivatePortfolioDto(); + + List result = new LinkedList<>(); + ResultHandler handler = resultContext -> result.add(resultContext.getResultObject()); + projectDao.scrollEntitiesForIndexing(db.getSession(), "unknown", handler); + + assertThat(result).isEmpty(); + } + private void insertDefaultQualityProfile(String language) { QProfileDto profile = db.qualityProfiles().insert(qp -> qp.setIsBuiltIn(true).setLanguage(language)); db.qualityProfiles().setAsDefault(profile); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java index 94c9547be06..22ca24a9df2 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java @@ -239,17 +239,6 @@ public class ComponentDao implements Dao { return mapper(session).selectProjectsFromView("%." + escapedViewUuid + ".%", rootViewUuid); } - /** - * Selects all components that are relevant for indexing. The result is not returned (since it is usually too big), but handed over to the handler - * - * @param session the database session - * @param branchUuid the branch uuid, which is selected with all of its children - * @param handler the action to be applied to every result - */ - public void scrollForIndexing(DbSession session, @Nullable String branchUuid, ResultHandler handler) { - mapper(session).scrollForIndexing(branchUuid, handler); - } - /** * Retrieve enabled components keys with given qualifiers *

diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java index bf0a8312e8a..1e954409aa0 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java @@ -92,8 +92,6 @@ public interface ComponentMapper { */ List selectProjectsFromView(@Param("viewUuidLikeQuery") String viewUuidLikeQuery, @Param("rootViewUuid") String rootViewUuid); - void scrollForIndexing(@Param("branchUuid") @Nullable String branchUuid, ResultHandler handler); - void scrollAllFilesForFileMove(@Param("branchUuid") String branchUuid, ResultHandler handler); void insert(ComponentDto componentDto); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java index 27ab59c83d3..1d354a8487a 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java @@ -20,11 +20,11 @@ package org.sonar.db.project; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; import javax.annotation.Nullable; +import org.apache.ibatis.session.ResultHandler; import org.sonar.api.utils.System2; import org.sonar.db.Dao; import org.sonar.db.DbSession; @@ -155,7 +155,8 @@ public class ProjectDao implements Dao { if (uuids.isEmpty()) { return emptyList(); } - return mapper(dbSession).selectEntitiesByUuids(uuids); + + return executeLargeInputs(uuids, partition -> mapper(dbSession).selectEntitiesByUuids(partition)); } public Optional selectEntityByKey(DbSession dbSession, String key) { @@ -166,8 +167,10 @@ public class ProjectDao implements Dao { if (keys.isEmpty()) { return emptyList(); } - return mapper(dbSession).selectEntitiesByKeys(keys); + return executeLargeInputs(keys, partition -> mapper(dbSession).selectEntitiesByKeys(partition)); } - + public void scrollEntitiesForIndexing(DbSession session, @Nullable String entityUuid, ResultHandler handler) { + mapper(session).scrollEntitiesForIndexing(entityUuid, handler); + } } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java index 21f3953c2c7..6ffcf920733 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java @@ -25,6 +25,7 @@ import java.util.Set; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.session.ResultHandler; import org.sonar.db.entity.EntityDto; public interface ProjectMapper { @@ -82,4 +83,6 @@ public interface ProjectMapper { EntityDto selectEntityByKey(String key); List selectEntitiesByKeys(@Param("keys") Collection keys); + + void scrollEntitiesForIndexing(@Param("entityUuid") @Nullable String entityUuid, ResultHandler handler); } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml index 136b85e5ba5..7f897a7090f 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml @@ -481,22 +481,6 @@ - - + ) + + + diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/property/PropertyTesting.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/property/PropertyTesting.java index 6542ac1fbee..70c13995cac 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/property/PropertyTesting.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/property/PropertyTesting.java @@ -63,18 +63,6 @@ public class PropertyTesting { return newPropertyDto(null, user.getUuid()); } - public static PropertyDto newPropertyDto(String key, String value, ComponentDto component, UserDto user) { - checkNotNull(component.uuid()); - checkNotNull(user.getUuid()); - return newPropertyDto(key, value, component.uuid(), user.getUuid()); - } - - public static PropertyDto newPropertyDto(ComponentDto component, UserDto user) { - checkNotNull(component.uuid()); - checkNotNull(user.getUuid()); - return newPropertyDto(component.uuid(), user.getUuid()); - } - private static PropertyDto newPropertyDto(@Nullable String componentUuid, @Nullable String userUuid) { String key = String.valueOf(cursor); cursor++; diff --git a/server/sonar-server-common/src/it/java/org/sonar/server/component/index/ComponentIndexerIT.java b/server/sonar-server-common/src/it/java/org/sonar/server/component/index/ComponentIndexerIT.java index c8889b328e7..4835bc85c94 100644 --- a/server/sonar-server-common/src/it/java/org/sonar/server/component/index/ComponentIndexerIT.java +++ b/server/sonar-server-common/src/it/java/org/sonar/server/component/index/ComponentIndexerIT.java @@ -103,7 +103,6 @@ public class ComponentIndexerIT { ComponentDoc doc = es.getDocuments(TYPE_COMPONENT, ComponentDoc.class).get(0); assertThat(doc.getId()).isEqualTo(project.uuid()); assertThat(doc.getKey()).isEqualTo(project.getKey()); - assertThat(doc.getProjectUuid()).isEqualTo(project.branchUuid()); assertThat(doc.getName()).isEqualTo(project.name()); } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentDoc.java b/server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentDoc.java index 4e8a657bcb7..d2fff419631 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentDoc.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentDoc.java @@ -20,13 +20,10 @@ package org.sonar.server.component.index; import java.util.HashMap; -import java.util.Map; import org.sonar.server.es.BaseDoc; -import org.sonar.server.permission.index.AuthorizationDoc; import static org.sonar.server.component.index.ComponentIndexDefinition.FIELD_KEY; import static org.sonar.server.component.index.ComponentIndexDefinition.FIELD_NAME; -import static org.sonar.server.component.index.ComponentIndexDefinition.FIELD_PROJECT_UUID; import static org.sonar.server.component.index.ComponentIndexDefinition.FIELD_QUALIFIER; import static org.sonar.server.component.index.ComponentIndexDefinition.FIELD_UUID; import static org.sonar.server.component.index.ComponentIndexDefinition.TYPE_COMPONENT; @@ -37,10 +34,6 @@ public class ComponentDoc extends BaseDoc { super(TYPE_COMPONENT, new HashMap<>(6)); } - public ComponentDoc(Map fields) { - super(TYPE_COMPONENT, fields); - } - @Override public String getId() { return getField(FIELD_UUID); @@ -51,16 +44,6 @@ public class ComponentDoc extends BaseDoc { return this; } - public String getProjectUuid() { - return getField(FIELD_PROJECT_UUID); - } - - public ComponentDoc setProjectUuid(String s) { - setField(FIELD_PROJECT_UUID, s); - setParent(AuthorizationDoc.idOf(s)); - return this; - } - public String getKey() { return getField(FIELD_KEY); } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentIndexDefinition.java b/server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentIndexDefinition.java index bdb00e26b41..8c8d295d0a0 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentIndexDefinition.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentIndexDefinition.java @@ -43,7 +43,6 @@ public class ComponentIndexDefinition implements IndexDefinition { public static final Index DESCRIPTOR = Index.withRelations("components"); public static final IndexType.IndexRelationType TYPE_COMPONENT = IndexType.relation(IndexType.main(DESCRIPTOR, TYPE_AUTHORIZATION), "component"); public static final String FIELD_UUID = "uuid"; - public static final String FIELD_PROJECT_UUID = "project_uuid"; public static final String FIELD_KEY = "key"; public static final String FIELD_NAME = "name"; public static final String FIELD_QUALIFIER = "qualifier"; @@ -85,7 +84,6 @@ public class ComponentIndexDefinition implements IndexDefinition { TypeMapping mapping = index.createTypeMapping(TYPE_COMPONENT); mapping.keywordFieldBuilder(FIELD_UUID).disableNorms().build(); - mapping.keywordFieldBuilder(FIELD_PROJECT_UUID).disableNorms().build(); mapping.keywordFieldBuilder(FIELD_KEY).addSubFields(SORTABLE_ANALYZER).build(); mapping.textFieldBuilder(FIELD_NAME) .withFieldData() diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentIndexer.java b/server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentIndexer.java index 2890a3809ec..c3287289257 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentIndexer.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentIndexer.java @@ -33,7 +33,7 @@ import org.elasticsearch.search.builder.SearchSourceBuilder; 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.entity.EntityDto; import org.sonar.db.es.EsQueueDto; import org.sonar.server.es.BaseDoc; import org.sonar.server.es.BulkIndexer; @@ -100,7 +100,7 @@ public class ComponentIndexer implements ProjectIndexer, NeedAuthorizationIndexe return emptyList(); case PROJECT_CREATION, PROJECT_DELETION, PROJECT_KEY_UPDATE: List items = projectUuids.stream() - .map(branchUuid -> EsQueueDto.create(TYPE_COMPONENT.format(), branchUuid, null, branchUuid)) + .map(projectUuid -> EsQueueDto.create(TYPE_COMPONENT.format(), projectUuid, null, projectUuid)) .collect(MoreCollectors.toArrayList(projectUuids.size())); return dbClient.esQueueDao().insert(dbSession, items); default: @@ -118,15 +118,14 @@ public class ComponentIndexer implements ProjectIndexer, NeedAuthorizationIndexe OneToManyResilientIndexingListener listener = new OneToManyResilientIndexingListener(dbClient, dbSession, items); BulkIndexer bulkIndexer = new BulkIndexer(esClient, TYPE_COMPONENT, Size.REGULAR, listener); bulkIndexer.start(); - Set branchUuids = items.stream().map(EsQueueDto::getDocId).collect(MoreCollectors.toHashSet(items.size())); - Set remaining = new HashSet<>(branchUuids); + Set entityUuids = items.stream().map(EsQueueDto::getDocId).collect(MoreCollectors.toHashSet(items.size())); + Set remaining = new HashSet<>(entityUuids); - for (String branchUuid : branchUuids) { - // TODO allow scrolling multiple projects at the same time - dbClient.componentDao().scrollForIndexing(dbSession, branchUuid, context -> { - ComponentDto dto = context.getResultObject(); + for (String entityUuid : entityUuids) { + dbClient.projectDao().scrollEntitiesForIndexing(dbSession, entityUuid, context -> { + EntityDto dto = context.getResultObject(); bulkIndexer.add(toDocument(dto).toIndexRequest()); - remaining.remove(dto.branchUuid()); + remaining.remove(dto.getUuid()); }); } @@ -139,16 +138,16 @@ public class ComponentIndexer implements ProjectIndexer, NeedAuthorizationIndexe /** * @param projectUuid the uuid of the project to analyze, or {@code null} if all content should be indexed.
- * Warning: only use {@code null} during startup. + * Warning: only use {@code null} during startup. */ private void doIndexByProjectUuid(@Nullable String projectUuid, Size bulkSize) { BulkIndexer bulk = new BulkIndexer(esClient, TYPE_COMPONENT, bulkSize); bulk.start(); try (DbSession dbSession = dbClient.openSession(false)) { - dbClient.componentDao() - .scrollForIndexing(dbSession, projectUuid, context -> { - ComponentDto dto = context.getResultObject(); + dbClient.projectDao() + .scrollEntitiesForIndexing(dbSession, projectUuid, context -> { + EntityDto dto = context.getResultObject(); bulk.add(toDocument(dto).toIndexRequest()); }); } @@ -157,7 +156,7 @@ public class ComponentIndexer implements ProjectIndexer, NeedAuthorizationIndexe private static void addProjectDeletionToBulkIndexer(BulkIndexer bulkIndexer, String projectUuid) { SearchRequest searchRequest = EsClient.prepareSearch(TYPE_COMPONENT.getMainType()) - .source(new SearchSourceBuilder().query(QueryBuilders.termQuery(ComponentIndexDefinition.FIELD_PROJECT_UUID, projectUuid))) + .source(new SearchSourceBuilder().query(QueryBuilders.termQuery(ComponentIndexDefinition.FIELD_UUID, projectUuid))) .routing(AuthorizationDoc.idOf(projectUuid)); bulkIndexer.addDeletion(searchRequest); } @@ -170,7 +169,7 @@ public class ComponentIndexer implements ProjectIndexer, NeedAuthorizationIndexe } @VisibleForTesting - void index(ComponentDto... docs) { + void index(EntityDto... docs) { BulkIndexer bulk = new BulkIndexer(esClient, TYPE_COMPONENT, Size.REGULAR); bulk.start(); Arrays.stream(docs) @@ -180,12 +179,11 @@ public class ComponentIndexer implements ProjectIndexer, NeedAuthorizationIndexe bulk.stop(); } - public static ComponentDoc toDocument(ComponentDto component) { + public static ComponentDoc toDocument(EntityDto component) { return new ComponentDoc() - .setId(component.uuid()) - .setName(component.name()) + .setId(component.getUuid()) + .setName(component.getName()) .setKey(component.getKey()) - .setProjectUuid(component.branchUuid()) - .setQualifier(component.qualifier()); + .setQualifier(component.getQualifier()); } } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/AddActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/AddActionIT.java index 9feaba8aaf4..b51e9620c92 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/AddActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/AddActionIT.java @@ -64,7 +64,7 @@ public class AddActionIT { private final DbClient dbClient = db.getDbClient(); private final DbSession dbSession = db.getSession(); private final FavoriteUpdater favoriteUpdater = new FavoriteUpdater(dbClient); - private final WsActionTester ws = new WsActionTester(new AddAction(userSession, dbClient, favoriteUpdater, TestComponentFinder.from(db))); + private final WsActionTester ws = new WsActionTester(new AddAction(userSession, dbClient, favoriteUpdater)); @Test public void add_a_project() { diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/RemoveActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/RemoveActionIT.java index f2636b299b3..6aea81b54fe 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/RemoveActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/RemoveActionIT.java @@ -55,7 +55,7 @@ public class RemoveActionIT { private final DbClient dbClient = db.getDbClient(); private final FavoriteUpdater favoriteUpdater = new FavoriteUpdater(dbClient); - private final WsActionTester ws = new WsActionTester(new RemoveAction(userSession, dbClient, favoriteUpdater, TestComponentFinder.from(db))); + private final WsActionTester ws = new WsActionTester(new RemoveAction(userSession, dbClient, favoriteUpdater)); @Before public void before() { @@ -75,11 +75,11 @@ public class RemoveActionIT { @Test public void fail_if_not_already_a_favorite() { - ProjectDto componentDto = insertProjectAndPermissions(); + ProjectDto project = insertProjectAndPermissions(); assertThatThrownBy(() -> call(PROJECT_KEY)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Component '" + PROJECT_KEY + "' (uuid: " + componentDto.getUuid() + ") is not a favorite"); + .hasMessage("Component '" + PROJECT_KEY + "' (uuid: " + project.getUuid() + ") is not a favorite"); } @Test diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ListDefinitionsActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ListDefinitionsActionIT.java index 40c4469e5a2..4fc97352a34 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ListDefinitionsActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ListDefinitionsActionIT.java @@ -33,10 +33,8 @@ import org.sonar.api.utils.System2; import org.sonar.api.web.UserRole; import org.sonar.db.DbClient; import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDbTester; -import org.sonar.db.component.ComponentDto; import org.sonar.db.permission.GlobalPermission; -import org.sonar.server.component.TestComponentFinder; +import org.sonar.db.project.ProjectDto; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.tester.UserSessionRule; @@ -73,16 +71,14 @@ public class ListDefinitionsActionIT { public DbTester db = DbTester.create(System2.INSTANCE); private final DbClient dbClient = db.getDbClient(); - private final ComponentDbTester componentDb = new ComponentDbTester(db); - private ComponentDto project; + private ProjectDto project; private final PropertyDefinitions propertyDefinitions = new PropertyDefinitions(System2.INSTANCE); private final SettingsWsSupport support = new SettingsWsSupport(userSession); - private final WsActionTester ws = new WsActionTester( - new ListDefinitionsAction(dbClient, TestComponentFinder.from(db), userSession, propertyDefinitions, support)); + private final WsActionTester ws = new WsActionTester(new ListDefinitionsAction(dbClient, userSession, propertyDefinitions, support)); @Before public void setUp() { - project = db.components().insertPrivateProject().getMainBranchComponent(); + project = db.components().insertPrivateProject().getProjectDto(); } @Test diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ResetActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ResetActionIT.java index 5d18dd2220f..a8eadfc7d1d 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ResetActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ResetActionIT.java @@ -75,12 +75,11 @@ public class ResetActionIT { private final PropertyDbTester propertyDb = new PropertyDbTester(db); private final DbClient dbClient = db.getDbClient(); private final DbSession dbSession = db.getSession(); - private final ComponentFinder componentFinder = TestComponentFinder.from(db); private final PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE); private final SettingsUpdater settingsUpdater = new SettingsUpdater(dbClient, definitions); private final SettingValidations settingValidations = new SettingValidations(definitions, dbClient, i18n); private ProjectDto project; - private final ResetAction underTest = new ResetAction(dbClient, componentFinder, settingsUpdater, userSession, definitions, settingValidations); + private final ResetAction underTest = new ResetAction(dbClient, settingsUpdater, userSession, definitions, settingValidations); private final WsActionTester ws = new WsActionTester(underTest); @Before @@ -218,7 +217,7 @@ public class ResetActionIT { assertThat(action.isInternal()).isFalse(); assertThat(action.isPost()).isTrue(); assertThat(action.responseExampleAsString()).isNull(); - assertThat(action.params()).extracting(Param::key).containsExactlyInAnyOrder("keys", "component", "branch", "pullRequest"); + assertThat(action.params()).extracting(Param::key).containsExactlyInAnyOrder("keys", "component"); } @Test diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/SetActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/SetActionIT.java index a7f16712833..44caee87e40 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/SetActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/SetActionIT.java @@ -52,8 +52,6 @@ import org.sonar.db.property.PropertyDto; import org.sonar.db.property.PropertyQuery; import org.sonar.process.ProcessProperties; import org.sonar.scanner.protocol.GsonHelper; -import org.sonar.server.component.ComponentFinder; -import org.sonar.server.component.TestComponentFinder; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; @@ -87,14 +85,12 @@ public class SetActionIT { private PropertyDbTester propertyDb = new PropertyDbTester(db); private DbClient dbClient = db.getDbClient(); private DbSession dbSession = db.getSession(); - private ComponentFinder componentFinder = TestComponentFinder.from(db); - private I18nRule i18n = new I18nRule(); private PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE); private FakeSettingsNotifier settingsChangeNotifier = new FakeSettingsNotifier(dbClient); private SettingsUpdater settingsUpdater = new SettingsUpdater(dbClient, definitions); private SettingValidations validations = new SettingValidations(definitions, dbClient, i18n); - private SetAction underTest = new SetAction(definitions, dbClient, componentFinder, userSession, settingsUpdater, settingsChangeNotifier, validations); + private SetAction underTest = new SetAction(definitions, dbClient, userSession, settingsUpdater, settingsChangeNotifier, validations); private WsActionTester ws = new WsActionTester(underTest); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ValuesActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ValuesActionIT.java index cea85076cc1..58dd418deb8 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ValuesActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ValuesActionIT.java @@ -82,15 +82,13 @@ public class ValuesActionIT { private final DbClient dbClient = db.getDbClient(); private final PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE); private final SettingsWsSupport support = new SettingsWsSupport(userSession); - private final WsActionTester wsActionTester = new WsActionTester(new ValuesAction(dbClient, TestComponentFinder.from(db), userSession, definitions, support)); + private final WsActionTester wsActionTester = new WsActionTester(new ValuesAction(dbClient, userSession, definitions, support)); private ProjectDto project; - private ComponentDto rootComponent; @Before public void setUp() { ProjectData projectData = db.components().insertPrivateProject(); project = projectData.getProjectDto(); - rootComponent = projectData.getMainBranchComponent(); } @Test diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java index 67cadf61d4f..d59f089cb3b 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java @@ -159,7 +159,7 @@ public class SuggestionsAction implements ComponentsWsAction { } /** - * we are generating suggestions, by using (1) favorites and (2) recently browsed components (without searchin in Elasticsearch) + * we are generating suggestions, by using (1) favorites and (2) recently browsed components (without searching in Elasticsearch) */ private SuggestionsWsResponse loadSuggestionsWithoutSearch(int skip, int limit, Set recentlyBrowsedKeys, List qualifiers) { List favorites = favoriteFinder.list(); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/FavoriteFinder.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/FavoriteFinder.java index b31f0153500..5e35111dbf3 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/FavoriteFinder.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/FavoriteFinder.java @@ -55,9 +55,9 @@ public class FavoriteFinder { .setKey(PROP_FAVORITE_KEY) .setUserUuid(userSession.getUuid()) .build(); - Set componentUuids = dbClient.propertiesDao().selectByQuery(dbQuery, dbSession).stream().map(PropertyDto::getComponentUuid).collect(Collectors.toSet()); + Set entitiesUuids = dbClient.propertiesDao().selectByQuery(dbQuery, dbSession).stream().map(PropertyDto::getComponentUuid).collect(Collectors.toSet()); - List entities = dbClient.projectDao().selectEntitiesByUuids(dbSession, componentUuids); + List entities = dbClient.projectDao().selectEntitiesByUuids(dbSession, entitiesUuids); return entities.stream() .sorted(Comparator.comparing(EntityDto::getName)) diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/AddAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/AddAction.java index a233f317cab..a5618d94905 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/AddAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/AddAction.java @@ -54,21 +54,19 @@ public class AddAction implements FavoritesWsAction { private final UserSession userSession; private final DbClient dbClient; private final FavoriteUpdater favoriteUpdater; - private final ComponentFinder componentFinder; - public AddAction(UserSession userSession, DbClient dbClient, FavoriteUpdater favoriteUpdater, ComponentFinder componentFinder) { + public AddAction(UserSession userSession, DbClient dbClient, FavoriteUpdater favoriteUpdater) { this.userSession = userSession; this.dbClient = dbClient; this.favoriteUpdater = favoriteUpdater; - this.componentFinder = componentFinder; } @Override public void define(WebService.NewController context) { WebService.NewAction action = context.createAction("add") - .setDescription("Add a component (project, file etc.) as favorite for the authenticated user.
" + + .setDescription("Add a component (project, portfolio, etc.) as favorite for the authenticated user.
" + "Only 100 components by qualifier can be added as favorite.
" + - "Requires authentication and the following permission: 'Browse' on the project of the specified component.") + "Requires authentication and the following permission: 'Browse' on the component.") .setSince("6.3") .setChangelog( new Change("10.1", String.format("The use of module keys in parameter '%s' is removed", PARAM_COMPONENT)), diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/RemoveAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/RemoveAction.java index af6cf40038b..85cc8d60a11 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/RemoveAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/RemoveAction.java @@ -40,13 +40,11 @@ public class RemoveAction implements FavoritesWsAction { private final UserSession userSession; private final DbClient dbClient; private final FavoriteUpdater favoriteUpdater; - private final ComponentFinder componentFinder; - public RemoveAction(UserSession userSession, DbClient dbClient, FavoriteUpdater favoriteUpdater, ComponentFinder componentFinder) { + public RemoveAction(UserSession userSession, DbClient dbClient, FavoriteUpdater favoriteUpdater) { this.userSession = userSession; this.dbClient = dbClient; this.favoriteUpdater = favoriteUpdater; - this.componentFinder = componentFinder; } @Override diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ListDefinitionsAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ListDefinitionsAction.java index c14b2b1391c..cc68222591b 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ListDefinitionsAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ListDefinitionsAction.java @@ -32,13 +32,14 @@ import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.server.component.ComponentFinder; +import org.sonar.db.entity.EntityDto; +import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.user.UserSession; import org.sonarqube.ws.Settings; import org.sonarqube.ws.Settings.ListDefinitionsWsResponse; import static com.google.common.base.Strings.emptyToNull; +import static java.lang.String.format; import static java.util.Comparator.comparing; import static java.util.Optional.ofNullable; import static org.sonar.api.web.UserRole.USER; @@ -49,15 +50,12 @@ import static org.sonar.server.ws.WsUtils.writeProtobuf; public class ListDefinitionsAction implements SettingsWsAction { private final DbClient dbClient; - private final ComponentFinder componentFinder; private final UserSession userSession; private final PropertyDefinitions propertyDefinitions; private final SettingsWsSupport settingsWsSupport; - public ListDefinitionsAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, PropertyDefinitions propertyDefinitions, - SettingsWsSupport settingsWsSupport) { + public ListDefinitionsAction(DbClient dbClient, UserSession userSession, PropertyDefinitions propertyDefinitions, SettingsWsSupport settingsWsSupport) { this.dbClient = dbClient; - this.componentFinder = componentFinder; this.userSession = userSession; this.propertyDefinitions = propertyDefinitions; this.settingsWsSupport = settingsWsSupport; @@ -93,8 +91,8 @@ public class ListDefinitionsAction implements SettingsWsAction { private ListDefinitionsWsResponse doHandle(Request request) { ListDefinitionsRequest wsRequest = toWsRequest(request); - Optional component = loadComponent(wsRequest); - Optional qualifier = getQualifier(component); + Optional component = loadComponent(wsRequest); + Optional qualifier = component.map(EntityDto::getQualifier); ListDefinitionsWsResponse.Builder wsResponse = ListDefinitionsWsResponse.newBuilder(); propertyDefinitions.getAll().stream() .filter(definition -> qualifier.map(s -> definition.qualifiers().contains(s)).orElseGet(definition::global)) @@ -111,19 +109,16 @@ public class ListDefinitionsAction implements SettingsWsAction { .setComponent(request.param(PARAM_COMPONENT)); } - private static Optional getQualifier(Optional component) { - return component.map(ComponentDto::qualifier); - } - - private Optional loadComponent(ListDefinitionsRequest request) { + private Optional loadComponent(ListDefinitionsRequest request) { try (DbSession dbSession = dbClient.openSession(false)) { - String componentKey = request.getComponent(); - if (componentKey == null) { + String entityKey = request.getComponent(); + if (entityKey == null) { return Optional.empty(); } - ComponentDto component = componentFinder.getByKey(dbSession, componentKey); - userSession.checkComponentPermission(USER, component); - return Optional.of(component); + EntityDto entity = dbClient.projectDao().selectEntityByKey(dbSession, entityKey) + .orElseThrow(() -> new NotFoundException(format("Component key '%s' not found", entityKey))); + userSession.checkEntityPermission(USER, entity); + return Optional.of(entity); } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ResetAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ResetAction.java index 4c2383cbc38..e8093749264 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ResetAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ResetAction.java @@ -34,9 +34,7 @@ import org.sonar.api.web.UserRole; 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.entity.EntityDto; -import org.sonar.server.component.ComponentFinder; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.setting.ws.SettingValidations.SettingData; import org.sonar.server.user.UserSession; @@ -47,24 +45,19 @@ import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_BRANCH; import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_COMPONENT; import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_KEYS; import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_PULL_REQUEST; -import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; -import static org.sonar.server.ws.KeyExamples.KEY_PULL_REQUEST_EXAMPLE_001; public class ResetAction implements SettingsWsAction { private final DbClient dbClient; - private final ComponentFinder componentFinder; private final SettingsUpdater settingsUpdater; private final UserSession userSession; private final PropertyDefinitions definitions; private final SettingValidations validations; - public ResetAction(DbClient dbClient, ComponentFinder componentFinder, SettingsUpdater settingsUpdater, UserSession userSession, PropertyDefinitions definitions, - SettingValidations validations) { + public ResetAction(DbClient dbClient, SettingsUpdater settingsUpdater, UserSession userSession, PropertyDefinitions definitions, SettingValidations validations) { this.dbClient = dbClient; this.settingsUpdater = settingsUpdater; this.userSession = userSession; - this.componentFinder = componentFinder; this.definitions = definitions; this.validations = validations; } @@ -81,8 +74,9 @@ public class ResetAction implements SettingsWsAction { "") .setSince("6.1") .setChangelog( + new Change("10.1", format("Internal parameters '%s' and '%s' were removed", PARAM_BRANCH, PARAM_PULL_REQUEST)), new Change("8.8", "Deprecated parameter 'componentKey' has been removed"), - new Change("7.6", String.format("The use of module keys in parameter '%s' is deprecated", PARAM_COMPONENT)), + new Change("7.6", format("The use of module keys in parameter '%s' is deprecated", PARAM_COMPONENT)), new Change("7.1", "The settings defined in conf/sonar.properties are read-only and can't be changed")) .setPost(true) .setHandler(this); @@ -94,16 +88,6 @@ public class ResetAction implements SettingsWsAction { action.createParam(PARAM_COMPONENT) .setDescription("Component key") .setExampleValue(KEY_PROJECT_EXAMPLE_001); - action.createParam(PARAM_BRANCH) - .setDescription("Branch key") - .setExampleValue(KEY_BRANCH_EXAMPLE_001) - .setInternal(true) - .setSince("6.6"); - action.createParam(PARAM_PULL_REQUEST) - .setDescription("Pull request id") - .setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001) - .setInternal(true) - .setSince("7.1"); } @Override @@ -115,8 +99,7 @@ public class ResetAction implements SettingsWsAction { resetRequest.getKeys().forEach(key -> { SettingsWsSupport.validateKey(key); SettingData data = new SettingData(key, emptyList(), component.orElse(null)); - List.of(validations.scope(), validations.qualifier()) - .forEach(validation -> validation.accept(data)); + List.of(validations.scope(), validations.qualifier()).forEach(validation -> validation.accept(data)); }); List keys = getKeys(resetRequest); @@ -142,9 +125,7 @@ public class ResetAction implements SettingsWsAction { private static ResetRequest toWsRequest(Request request) { return new ResetRequest() .setKeys(request.mandatoryParamAsStrings(PARAM_KEYS)) - .setComponent(request.param(PARAM_COMPONENT)) - .setBranch(request.param(PARAM_BRANCH)) - .setPullRequest(request.param(PARAM_PULL_REQUEST)); + .setComponent(request.param(PARAM_COMPONENT)); } private Optional getComponent(DbSession dbSession, ResetRequest request) { @@ -153,7 +134,6 @@ public class ResetAction implements SettingsWsAction { return Optional.empty(); } - // TODO this WS should support branches and PRs? return Optional.of(dbClient.projectDao().selectEntityByKey(dbSession, componentKey) .orElseThrow(() -> new NotFoundException(format("Component key '%s' not found", componentKey)))); } @@ -167,32 +147,9 @@ public class ResetAction implements SettingsWsAction { } private static class ResetRequest { - - private String branch; - private String pullRequest; private String component; private List keys; - public ResetRequest setBranch(@Nullable String branch) { - this.branch = branch; - return this; - } - - @CheckForNull - public String getBranch() { - return branch; - } - - public ResetRequest setPullRequest(@Nullable String pullRequest) { - this.pullRequest = pullRequest; - return this; - } - - @CheckForNull - public String getPullRequest() { - return pullRequest; - } - public ResetRequest setComponent(@Nullable String component) { this.component = component; return this; diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SetAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SetAction.java index 3257522f33d..c7d50a66de0 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SetAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SetAction.java @@ -47,11 +47,9 @@ 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.ComponentDto; import org.sonar.db.entity.EntityDto; import org.sonar.db.property.PropertyDto; import org.sonar.scanner.protocol.GsonHelper; -import org.sonar.server.component.ComponentFinder; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.setting.SettingsChangeNotifier; @@ -75,17 +73,15 @@ public class SetAction implements SettingsWsAction { private final PropertyDefinitions propertyDefinitions; private final DbClient dbClient; - private final ComponentFinder componentFinder; private final UserSession userSession; private final SettingsUpdater settingsUpdater; private final SettingsChangeNotifier settingsChangeNotifier; private final SettingValidations validations; - public SetAction(PropertyDefinitions propertyDefinitions, DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, + public SetAction(PropertyDefinitions propertyDefinitions, DbClient dbClient, UserSession userSession, SettingsUpdater settingsUpdater, SettingsChangeNotifier settingsChangeNotifier, SettingValidations validations) { this.propertyDefinitions = propertyDefinitions; this.dbClient = dbClient; - this.componentFinder = componentFinder; this.userSession = userSession; this.settingsUpdater = settingsUpdater; this.settingsChangeNotifier = settingsChangeNotifier; diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingValidations.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingValidations.java index dbe09a53427..c978d12d3cf 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingValidations.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingValidations.java @@ -54,7 +54,7 @@ import static java.util.Objects.requireNonNull; import static org.sonar.server.exceptions.BadRequestException.checkRequest; public class SettingValidations { - private static final Collection SECURITY_JSON_PROPERTIES = List.of( + private static final Set SECURITY_JSON_PROPERTIES = Set.of( "sonar.security.config.javasecurity", "sonar.security.config.phpsecurity", "sonar.security.config.pythonsecurity", diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java index 551025aa3ce..e95241f75a2 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java @@ -25,6 +25,7 @@ import java.util.Set; import org.sonar.api.server.ServerSide; import org.sonar.api.web.UserRole; import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.permission.GlobalPermission; import org.sonar.process.ProcessProperties; import org.sonar.server.user.UserSession; @@ -54,14 +55,14 @@ public class SettingsWsSupport { }); } - boolean isVisible(String key, Optional component) { + boolean isVisible(String key, Optional component) { if (isAdmin(component)) { return true; } return hasPermission(GlobalPermission.SCAN, UserRole.SCAN, component) || !isProtected(key); } - private boolean isAdmin(Optional component) { + private boolean isAdmin(Optional component) { return userSession.isSystemAdministrator() || hasPermission(GlobalPermission.ADMINISTER, ADMIN, component); } @@ -77,12 +78,12 @@ public class SettingsWsSupport { return ADMIN_ONLY_SETTINGS.contains(key); } - private boolean hasPermission(GlobalPermission orgPermission, String projectPermission, Optional component) { + private boolean hasPermission(GlobalPermission orgPermission, String projectPermission, Optional component) { if (userSession.hasPermission(orgPermission)) { return true; } return component - .map(c -> userSession.hasComponentPermission(projectPermission, c)) + .map(c -> userSession.hasEntityPermission(projectPermission, c)) .orElse(false); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ValuesAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ValuesAction.java index 7157264aded..6c996322b28 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ValuesAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ValuesAction.java @@ -21,9 +21,6 @@ package org.sonar.server.setting.ws; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Multimap; -import com.google.common.collect.Ordering; -import com.google.common.collect.TreeMultimap; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -46,12 +43,11 @@ 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.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.permission.GlobalPermission; import org.sonar.db.property.PropertyDto; import org.sonar.markdown.Markdown; -import org.sonar.server.component.ComponentFinder; +import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.user.UserSession; import org.sonarqube.ws.Settings; import org.sonarqube.ws.Settings.ValuesWsResponse; @@ -78,15 +74,12 @@ public class ValuesAction implements SettingsWsAction { private static final Set SERVER_SETTING_KEYS = Set.of(SERVER_STARTTIME, SERVER_ID); private final DbClient dbClient; - private final ComponentFinder componentFinder; private final UserSession userSession; private final PropertyDefinitions propertyDefinitions; private final SettingsWsSupport settingsWsSupport; - public ValuesAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, PropertyDefinitions propertyDefinitions, - SettingsWsSupport settingsWsSupport) { + public ValuesAction(DbClient dbClient, UserSession userSession, PropertyDefinitions propertyDefinitions, SettingsWsSupport settingsWsSupport) { this.dbClient = dbClient; - this.componentFinder = componentFinder; this.userSession = userSession; this.propertyDefinitions = propertyDefinitions; this.settingsWsSupport = settingsWsSupport; @@ -125,7 +118,7 @@ public class ValuesAction implements SettingsWsAction { private ValuesWsResponse doHandle(Request request) { try (DbSession dbSession = dbClient.openSession(true)) { ValuesRequest valuesRequest = ValuesRequest.from(request); - Optional component = loadComponent(dbSession, valuesRequest); + Optional component = loadComponent(dbSession, valuesRequest); Set keys = loadKeys(valuesRequest); Map keysToDisplayMap = getKeysToDisplayMap(keys); List settings = loadSettings(dbSession, component, keysToDisplayMap.keySet()); @@ -145,23 +138,25 @@ public class ValuesAction implements SettingsWsAction { return result; } - private Optional loadComponent(DbSession dbSession, ValuesRequest valuesRequest) { + private Optional loadComponent(DbSession dbSession, ValuesRequest valuesRequest) { String componentKey = valuesRequest.getComponent(); if (componentKey == null) { return Optional.empty(); } - ComponentDto component = componentFinder.getByKey(dbSession, componentKey); - if (!userSession.hasComponentPermission(USER, component) && - !userSession.hasComponentPermission(UserRole.SCAN, component) && + EntityDto component = dbClient.projectDao().selectEntityByKey(dbSession, componentKey) + .orElseThrow(() -> new NotFoundException(format("Component key '%s' not found", componentKey))); + + if (!userSession.hasEntityPermission(USER, component) && + !userSession.hasEntityPermission(UserRole.SCAN, component) && !userSession.hasPermission(GlobalPermission.SCAN)) { throw insufficientPrivilegesException(); } return Optional.of(component); } - private List loadSettings(DbSession dbSession, Optional component, Set keys) { - // List of settings must be kept in the following orders : default -> global -> component -> branch + private List loadSettings(DbSession dbSession, Optional component, Set keys) { + // List of settings must be kept in the following orders : default -> global -> component List settings = new ArrayList<>(); settings.addAll(loadDefaultValues(keys)); settings.addAll(loadGlobalSettings(dbSession, keys)); @@ -171,22 +166,8 @@ public class ValuesAction implements SettingsWsAction { .toList(); } - private Collection loadComponentSettings(DbSession dbSession, ComponentDto componentDto, Set keys) { - BranchDto branchDto = componentFinder.getBranchByUuid(dbSession, componentDto.branchUuid()); - - List componentUuids = new LinkedList<>(); - if (!branchDto.isMain()) { - ComponentDto mainBranchComponent = componentFinder.getByKey(dbSession, componentDto.getKey()); - if (!mainBranchComponent.isRoot()) { - componentUuids.add(mainBranchComponent.branchUuid()); - } - componentUuids.add(mainBranchComponent.uuid()); - } - if (!componentDto.isRoot()) { - componentUuids.add(componentDto.branchUuid()); - } - componentUuids.add(componentDto.uuid()); - return loadComponentsSettings(dbSession, keys, componentUuids); + private Collection loadComponentSettings(DbSession dbSession, EntityDto entity, Set keys) { + return loadComponentSettings(dbSession, keys, entity.getUuid()); } private List loadDefaultValues(Set keys) { @@ -209,25 +190,24 @@ public class ValuesAction implements SettingsWsAction { List properties = dbClient.propertiesDao().selectGlobalPropertiesByKeys(dbSession, keys); List propertySets = dbClient.propertiesDao().selectGlobalPropertiesByKeys(dbSession, getPropertySetKeys(properties)); return properties.stream() - .map(property -> Setting.createFromDto(property, getPropertySets(property.getKey(), propertySets, null), propertyDefinitions.get(property.getKey()))) + .map(property -> Setting.createFromDto(property, filterPropertySets(property.getKey(), propertySets, null), propertyDefinitions.get(property.getKey()))) .toList(); } /** * Return list of settings by component uuids */ - private Collection loadComponentsSettings(DbSession dbSession, Set keys, List componentUuids) { - List properties = dbClient.propertiesDao().selectPropertiesByKeysAndComponentUuids(dbSession, keys, componentUuids); - List propertySets = dbClient.propertiesDao().selectPropertiesByKeysAndComponentUuids(dbSession, getPropertySetKeys(properties), componentUuids); + private Collection loadComponentSettings(DbSession dbSession, Set keys, String entityUuid) { + List properties = dbClient.propertiesDao().selectPropertiesByKeysAndComponentUuids(dbSession, keys, Set.of(entityUuid)); + List propertySets = dbClient.propertiesDao().selectPropertiesByKeysAndComponentUuids(dbSession, getPropertySetKeys(properties), Set.of(entityUuid)); - Multimap settingsByUuid = TreeMultimap.create(Ordering.explicit(componentUuids), Ordering.arbitrary()); + List settings = new LinkedList<>(); for (PropertyDto propertyDto : properties) { String componentUuid = propertyDto.getComponentUuid(); String propertyKey = propertyDto.getKey(); - settingsByUuid.put(componentUuid, - Setting.createFromDto(propertyDto, getPropertySets(propertyKey, propertySets, componentUuid), propertyDefinitions.get(propertyKey))); + settings.add(Setting.createFromDto(propertyDto, filterPropertySets(propertyKey, propertySets, componentUuid), propertyDefinitions.get(propertyKey))); } - return settingsByUuid.values(); + return settings; } private Set getPropertySetKeys(List properties) { @@ -238,7 +218,7 @@ public class ValuesAction implements SettingsWsAction { .collect(Collectors.toSet()); } - private static List getPropertySets(String propertyKey, List propertySets, @Nullable String componentUuid) { + private static List filterPropertySets(String propertyKey, List propertySets, @Nullable String componentUuid) { return propertySets.stream() .filter(propertyDto -> Objects.equals(propertyDto.getComponentUuid(), componentUuid)) .filter(propertyDto -> propertyDto.getKey().startsWith(propertyKey + ".")) @@ -247,14 +227,14 @@ public class ValuesAction implements SettingsWsAction { private class ValuesResponseBuilder { private final List settings; - private final Optional requestedComponent; + private final Optional requestedComponent; private final ValuesWsResponse.Builder valuesWsBuilder = ValuesWsResponse.newBuilder(); private final Map settingsBuilderByKey = new HashMap<>(); private final Map settingsByParentKey = new HashMap<>(); private final Map keysToDisplayMap; - ValuesResponseBuilder(List settings, Optional requestedComponent, Map keysToDisplayMap) { + ValuesResponseBuilder(List settings, Optional requestedComponent, Map keysToDisplayMap) { this.settings = settings; this.requestedComponent = requestedComponent; this.keysToDisplayMap = keysToDisplayMap; @@ -288,7 +268,7 @@ public class ValuesAction implements SettingsWsAction { private void setInherited(Setting setting, Settings.Setting.Builder valueBuilder) { boolean isDefault = setting.isDefault(); boolean isGlobal = !requestedComponent.isPresent(); - boolean isOnComponent = requestedComponent.isPresent() && Objects.equals(setting.getComponentUuid(), requestedComponent.get().uuid()); + boolean isOnComponent = requestedComponent.isPresent() && Objects.equals(setting.getComponentUuid(), requestedComponent.get().getUuid()); boolean isSet = isGlobal || isOnComponent; valueBuilder.setInherited(isDefault || !isSet); } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SettingsWsSupportTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SettingsWsSupportTest.java index f7b162812b3..23d80dd0edf 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SettingsWsSupportTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SettingsWsSupportTest.java @@ -31,9 +31,11 @@ import org.mockito.Mock; import org.sonar.api.web.UserRole; import org.sonar.db.component.ComponentDto; import org.sonar.db.permission.GlobalPermission; +import org.sonar.db.project.ProjectDto; import org.sonar.server.user.UserSession; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.openMocks; @@ -74,10 +76,8 @@ public class SettingsWsSupportTest { private final boolean hasComponentPermission; private final boolean expectedIsVisible; - @Mock - private ComponentDto componentDto; - @Mock - private UserSession userSession; + private final ProjectDto componentDto = mock(ProjectDto.class); + private final UserSession userSession = mock(UserSession.class); @InjectMocks private SettingsWsSupport settingsWsSupport; @@ -94,7 +94,7 @@ public class SettingsWsSupportTest { openMocks(this); when(userSession.isSystemAdministrator()).thenReturn(isAdmin); when(userSession.hasPermission(GlobalPermission.SCAN)).thenReturn(hasGlobalPermission); - when(userSession.hasComponentPermission(UserRole.SCAN, componentDto)).thenReturn(hasComponentPermission); + when(userSession.hasEntityPermission(UserRole.SCAN, componentDto)).thenReturn(hasComponentPermission); boolean isVisible = settingsWsSupport.isVisible(property, Optional.of(componentDto)); assertThat(isVisible).isEqualTo(expectedIsVisible); diff --git a/sonar-ws/src/main/protobuf/ws-components.proto b/sonar-ws/src/main/protobuf/ws-components.proto index f4b1cac6b6a..d51a8a2805b 100644 --- a/sonar-ws/src/main/protobuf/ws-components.proto +++ b/sonar-ws/src/main/protobuf/ws-components.proto @@ -48,10 +48,10 @@ message ShowWsResponse { // WS api/components/suggestions message SuggestionsWsResponse { - reserved 3; //drop organization repeated Category results = 1; optional string warning = 2; - repeated Project projects = 4; + reserved 3; //drop organization + reserved 4; //drop projects message Category { optional string q = 1; @@ -68,11 +68,6 @@ message SuggestionsWsResponse { optional bool isRecentlyBrowsed = 6; optional bool isFavorite = 7; } - - message Project { - optional string key = 1; - optional string name = 2; - } } // WS api/components/search_projects -- 2.39.5