]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-20664 - Add ProjectExportDao for all Export steps
authorBenjamin Campomenosi <benjamin.campomenosi@sonarsource.com>
Thu, 19 Oct 2023 21:03:56 +0000 (23:03 +0200)
committersonartech <sonartech@sonarsource.com>
Mon, 23 Oct 2023 20:02:43 +0000 (20:02 +0000)
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectexport/branches/ExportBranchesStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectexport/issue/ExportIssuesStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectexport/rule/ExportAdHocRulesStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectexport/steps/ExportLinksStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectexport/steps/ExportNewCodePeriodsStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectexport/steps/ExportSettingsStep.java
server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectExportDaoIT.java [new file with mode: 0644]
server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java
server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java
server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectExportDao.java [new file with mode: 0644]

index f1e5aad62aeb5d58ce9255582d3419763068618f..c1b4f2565fa424e215a883dcc9d6852b77b21e80 100644 (file)
@@ -30,7 +30,6 @@ import org.sonar.ce.task.step.ComputationStep;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.BranchDto;
-import org.sonar.db.project.ProjectExportMapper;
 
 import static java.lang.String.format;
 import static org.apache.commons.lang.StringUtils.defaultString;
@@ -54,7 +53,8 @@ public class ExportBranchesStep implements ComputationStep {
       try (DbSession dbSession = dbClient.openSession(false);
         StreamWriter<ProjectDump.Branch> output = dumpWriter.newStreamWriter(DumpElement.BRANCHES)) {
         ProjectDump.Branch.Builder builder = ProjectDump.Branch.newBuilder();
-        List<BranchDto> branches = dbSession.getMapper(ProjectExportMapper.class).selectBranchesForExport(projectHolder.projectDto().getUuid());
+        List<BranchDto> branches = dbClient.projectExportDao()
+          .selectBranchesForExport(dbSession, projectHolder.projectDto().getUuid());
         for (BranchDto branch : branches) {
           builder
             .clear()
index d0b92faf001bb347441aef60e9153fef7aa10709..071ae4ff510ede60b17cc1d8dd082867c35245fb 100644 (file)
@@ -42,7 +42,6 @@ import org.sonar.ce.task.step.ComputationStep;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.issue.IssueDto;
-import org.sonar.db.project.ProjectExportMapper;
 import org.sonar.db.protobuf.DbIssues;
 
 import static java.lang.String.format;
@@ -75,7 +74,8 @@ public class ExportIssuesStep implements ComputationStep {
     try (
       StreamWriter<ProjectDump.Issue> output = dumpWriter.newStreamWriter(DumpElement.ISSUES);
       DbSession dbSession = dbClient.openSession(false);
-      Cursor<IssueDto> issueDtoCursor = dbSession.getMapper(ProjectExportMapper.class).scrollIssueForExport(projectHolder.projectDto().getUuid())) {
+      Cursor<IssueDto> issueDtoCursor = dbClient.projectExportDao()
+        .scrollIssueForExport(dbSession, projectHolder.projectDto().getUuid())) {
       ProjectDump.Issue.Builder issueBuilder = ProjectDump.Issue.newBuilder();
       issueDtoCursor
         .forEach(issueDto -> {
index a20a5e5b8cd0072432b743bcd6551609efdc3858..4cd71979c97996eddd7e3aa5cff76a7c9680601a 100644 (file)
@@ -35,7 +35,6 @@ import org.sonar.ce.task.step.ComputationStep;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.issue.ImpactDto;
-import org.sonar.db.project.ProjectExportMapper;
 import org.sonar.db.rule.RuleDto;
 
 import static java.lang.String.format;
@@ -58,7 +57,8 @@ public class ExportAdHocRulesStep implements ComputationStep {
     try (
       StreamWriter<ProjectDump.AdHocRule> output = dumpWriter.newStreamWriter(DumpElement.AD_HOC_RULES);
       DbSession dbSession = dbClient.openSession(false);
-      Cursor<RuleDto> ruleDtoCursor = dbSession.getMapper(ProjectExportMapper.class).scrollAdhocRulesForExport(projectHolder.projectDto().getUuid())) {
+      Cursor<RuleDto> ruleDtoCursor = dbClient.projectExportDao()
+        .scrollAdhocRulesForExport(dbSession, projectHolder.projectDto().getUuid())) {
       ProjectDump.AdHocRule.Builder adHocRuleBuilder = ProjectDump.AdHocRule.newBuilder();
       ruleDtoCursor
         .forEach(ruleDto -> {
index 7e73f799cab66d06f45421abece6df31dc11db80..148731297a33ecf9c698d9d194c07307ecf2db88 100644 (file)
@@ -26,7 +26,6 @@ import org.sonar.ce.task.step.ComputationStep;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ProjectLinkDto;
-import org.sonar.db.project.ProjectExportMapper;
 
 import static java.lang.String.format;
 import static org.apache.commons.lang.StringUtils.defaultString;
@@ -51,7 +50,8 @@ public class ExportLinksStep implements ComputationStep {
       try (DbSession dbSession = dbClient.openSession(false);
         StreamWriter<ProjectDump.Link> linksWriter = dumpWriter.newStreamWriter(DumpElement.LINKS)) {
         ProjectDump.Link.Builder builder = ProjectDump.Link.newBuilder();
-        List<ProjectLinkDto> links = dbSession.getMapper(ProjectExportMapper.class).selectLinksForExport(projectHolder.projectDto().getUuid());
+        List<ProjectLinkDto> links = dbClient.projectExportDao()
+          .selectLinksForExport(dbSession, projectHolder.projectDto().getUuid());
         for (ProjectLinkDto link : links) {
           builder
             .clear()
index ed2ee7a06beaa0fa1e2e115c12548fe26db51033..6cdbee5173f3f02a6a94f47d92759302764989f5 100644 (file)
@@ -26,7 +26,6 @@ import org.sonar.ce.task.step.ComputationStep;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.newcodeperiod.NewCodePeriodDto;
-import org.sonar.db.project.ProjectExportMapper;
 
 import static java.lang.String.format;
 
@@ -50,8 +49,8 @@ public class ExportNewCodePeriodsStep implements ComputationStep {
       DbSession dbSession = dbClient.openSession(false)) {
 
       final ProjectDump.NewCodePeriod.Builder builder = ProjectDump.NewCodePeriod.newBuilder();
-      final List<NewCodePeriodDto> newCodePeriods = dbSession.getMapper(ProjectExportMapper.class)
-        .selectNewCodePeriodsForExport(projectHolder.projectDto().getUuid());
+      final List<NewCodePeriodDto> newCodePeriods = dbClient.projectExportDao()
+        .selectNewCodePeriodsForExport(dbSession, projectHolder.projectDto().getUuid());
       for (NewCodePeriodDto newCodePeriod : newCodePeriods) {
         builder.clear()
           .setUuid(newCodePeriod.getUuid())
index 65940ef4fa52fcfef3b2aaa45bba9f88b8874cd9..1a4404709d4c66e048b4798c2d2c69faa1666ec0 100644 (file)
@@ -26,7 +26,6 @@ import org.slf4j.LoggerFactory;
 import org.sonar.ce.task.step.ComputationStep;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
-import org.sonar.db.project.ProjectExportMapper;
 import org.sonar.db.property.PropertyDto;
 
 import static java.lang.String.format;
@@ -44,7 +43,7 @@ public class ExportSettingsStep implements ComputationStep {
   private final ProjectHolder projectHolder;
   private final DumpWriter dumpWriter;
 
-  public ExportSettingsStep(DbClient dbClient, ProjectHolder projectHolder,DumpWriter dumpWriter) {
+  public ExportSettingsStep(DbClient dbClient, ProjectHolder projectHolder, DumpWriter dumpWriter) {
     this.dbClient = dbClient;
     this.projectHolder = projectHolder;
     this.dumpWriter = dumpWriter;
@@ -58,7 +57,8 @@ public class ExportSettingsStep implements ComputationStep {
       DbSession dbSession = dbClient.openSession(false)) {
 
       final ProjectDump.Setting.Builder builder = ProjectDump.Setting.newBuilder();
-      final List<PropertyDto> properties = dbSession.getMapper(ProjectExportMapper.class).selectPropertiesForExport(projectHolder.projectDto().getUuid())
+      final List<PropertyDto> properties = dbClient.projectExportDao()
+        .selectPropertiesForExport(dbSession, projectHolder.projectDto().getUuid())
         .stream()
         .filter(dto -> dto.getEntityUuid() != null)
         .filter(dto -> !IGNORED_KEYS.contains(dto.getKey()))
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectExportDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectExportDaoIT.java
new file mode 100644 (file)
index 0000000..cc2ea36
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.project;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.commons.lang.RandomStringUtils;
+import org.apache.ibatis.cursor.Cursor;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.RuleType;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.BranchDto;
+import org.sonar.db.component.BranchType;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ProjectData;
+import org.sonar.db.component.ProjectLinkDto;
+import org.sonar.db.issue.IssueDto;
+import org.sonar.db.newcodeperiod.NewCodePeriodDto;
+import org.sonar.db.newcodeperiod.NewCodePeriodType;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.db.rule.RuleDto;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+
+public class ProjectExportDaoIT {
+
+  private final System2 system2 = new AlwaysIncreasingSystem2(1000L);
+
+  @Rule
+  public DbTester db = DbTester.create(system2);
+
+  private final ProjectExportDao projectExportDao = new ProjectExportDao();
+
+  @Test
+  public void selectBranchesForExport_shouldOnlyReturnBranchExcludedFromPurge() {
+    ProjectData projectData = db.components().insertPrivateProject("project-uuid");
+    BranchDto branchExcludedFromPurge = db.components().insertProjectBranch(projectData.getProjectDto(),
+      branch -> branch.setExcludeFromPurge(true));
+    db.components().insertProjectBranch(projectData.getProjectDto(),
+      branch -> branch.setBranchType(BranchType.PULL_REQUEST).setExcludeFromPurge(true));
+    db.components().insertProjectBranch(projectData.getProjectDto(),
+      branch -> branch.setBranchType(BranchType.PULL_REQUEST));
+    db.components().insertProjectBranch(projectData.getProjectDto());
+
+    List<BranchDto> exportedBranch = projectExportDao.selectBranchesForExport(db.getSession(), "project-uuid");
+
+    assertThat(exportedBranch)
+      .hasSize(2)
+      .containsOnly(projectData.getMainBranchDto(), branchExcludedFromPurge);
+  }
+
+  @Test
+  public void selectPropertiesForExport_shouldOnlyReturnProjectPropertiesNotLinkedToUser() {
+    db.components().insertPrivateProject("project-uuid");
+    PropertyDto userProjectProperty = new PropertyDto().setKey("userProjectProperty").setEntityUuid("project-uuid").setUserUuid("user-uuid");
+    PropertyDto globalProperty = new PropertyDto().setKey("globalProperty");
+    PropertyDto projectProperty = new PropertyDto().setKey("projectProperty").setEntityUuid("project-uuid");
+    db.properties().insertProperties(List.of(userProjectProperty, globalProperty, projectProperty), null, null, null, null);
+
+    List<PropertyDto> exportedProperties = projectExportDao.selectPropertiesForExport(db.getSession(), "project-uuid");
+
+    assertThat(exportedProperties)
+      .hasSize(1)
+      .extracting(PropertyDto::getKey).containsOnly("projectProperty");
+  }
+
+  @Test
+  public void selectLinksForExport_shouldReturnLinkOfProject() {
+    ProjectDto project = db.components().insertPrivateProject("project-uuid").getProjectDto();
+    db.projectLinks().insertCustomLink(project, link -> link.setName("customLink").setHref("www.customLink.com"));
+    db.projectLinks().insertProvidedLink(project, link -> link.setName("providedLink").setHref("www.providedLink.com"));
+    ProjectDto otherProject = db.components().insertPrivateProject("another-project").getProjectDto();
+    db.projectLinks().insertCustomLink(otherProject, link -> link.setName("customLink"));
+
+    List<ProjectLinkDto> exportedLinks = projectExportDao.selectLinksForExport(db.getSession(), "project-uuid");
+
+    assertThat(exportedLinks)
+      .hasSize(2)
+      .extracting("name", "href")
+      .containsOnly(tuple("customLink", "www.customLink.com"), tuple("providedLink", "www.providedLink.com"));
+  }
+
+  @Test
+  public void selectNewCodePeriodsForExport_shouldOnlyReturnGlobalNewCodePeriodOrNewCodePeriodOnBranchExcludedFromPurge() {
+    ProjectDto project = db.components().insertPrivateProject("project-uuid").getProjectDto();
+    BranchDto branchExcludedFromPurge = db.components().insertProjectBranch(project, branch -> branch.setExcludeFromPurge(true));
+    BranchDto branchNotExcludedFromPurge = db.components().insertProjectBranch(project);
+    db.newCodePeriods().insert(project.getUuid(), NewCodePeriodType.REFERENCE_BRANCH, "main");
+    db.newCodePeriods().insert(project.getUuid(), branchExcludedFromPurge.getUuid(), NewCodePeriodType.PREVIOUS_VERSION, null);
+    db.newCodePeriods().insert(project.getUuid(), branchNotExcludedFromPurge.getUuid(), NewCodePeriodType.NUMBER_OF_DAYS, "10");
+    db.newCodePeriods().insert(NewCodePeriodType.SPECIFIC_ANALYSIS, "uuid");
+
+    List<NewCodePeriodDto> exportedNewCodePeriods = projectExportDao.selectNewCodePeriodsForExport(db.getSession(), "project-uuid");
+
+    assertThat(exportedNewCodePeriods)
+      .hasSize(2)
+      .extracting("type", "value")
+      .containsOnly(tuple(NewCodePeriodType.REFERENCE_BRANCH, "main"), tuple(NewCodePeriodType.PREVIOUS_VERSION, null));
+  }
+
+  @Test
+  public void scrollAdhocRulesForExport_shouldOnlyReturnAdHocRulesNotRemovedAndActiveOnProjectBranchesExcludedFromPurge() {
+    ProjectData projectData = db.components().insertPrivateProject("project-uuid");
+    ComponentDto file = db.components().insertFile(projectData.getMainBranchDto());
+    ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
+    ComponentDto branchNotExcludedFromPurge = db.components().insertProjectBranch(mainBranchComponent);
+
+    RuleDto externalRule = insertRule("externalRule", true, false);
+    db.issues().insertIssue(externalRule, mainBranchComponent, file, issueDto -> issueDto.setKee("issue-externalRule"));
+    RuleDto adHocRule1 = insertRule("adHocRule1", false, true);
+    db.issues().insertIssue(adHocRule1, mainBranchComponent, file, issueDto -> issueDto.setKee("issue-adHocRule1"));
+    RuleDto adHocRule2 = insertRule("adHocRule2", false, true);
+    db.issues().insertIssue(adHocRule2, branchNotExcludedFromPurge, file, issueDto -> issueDto.setKee("issue-adHocRule2"));
+    RuleDto adHocRule3 = insertRule("adHocRule3", false, true, RuleStatus.REMOVED);
+    db.issues().insertIssue(adHocRule3, mainBranchComponent, file, issueDto -> issueDto.setKee("issue-adHocRule3"));
+    RuleDto adHocRule4 = insertRule("adHocRule4", false, true);
+    db.issues().insertIssue(adHocRule4, mainBranchComponent, file, issueDto -> issueDto.setKee("issue-adHocRule4").setStatus(Issue.STATUS_CLOSED));
+    RuleDto standardRule = insertRule("standardRule", false, false);
+    db.issues().insertIssue(standardRule, mainBranchComponent, file, issueDto -> issueDto.setKee("issue-standardRule"));
+
+    Cursor<RuleDto> ruleDtos = projectExportDao.scrollAdhocRulesForExport(db.getSession(), "project-uuid");
+    Set<RuleDto> ruleDtoSet = toSet(ruleDtos);
+
+    assertThat(ruleDtoSet)
+      .hasSize(1)
+      .extracting("uuid")
+      .containsOnly(adHocRule1.getUuid());
+
+  }
+
+  @Test
+  public void scrollIssueForExport_shouldOnlyReturnIssueWithRulesNotRemovedAndActiveOnProjectBranchesExcludedFromPurge() {
+    ProjectData projectData = db.components().insertPrivateProject("project-uuid");
+    ComponentDto file = db.components().insertFile(projectData.getMainBranchDto());
+    ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
+    ComponentDto branchNotExcludedFromPurge = db.components().insertProjectBranch(mainBranchComponent);
+
+    RuleDto rule1 = db.rules().insertRule(ruleDto -> ruleDto.setUuid("rule1"));
+    db.issues().insertIssue(rule1, mainBranchComponent, file, issueDto -> issueDto.setKee("issue1"));
+    db.issues().insertIssue(rule1, branchNotExcludedFromPurge, file, issueDto -> issueDto.setKee("issue2"));
+    RuleDto rule2 = db.rules().insertRule(ruleDto -> ruleDto.setUuid("rule2").setStatus(RuleStatus.REMOVED));
+    db.issues().insertIssue(rule2, mainBranchComponent, file, issueDto -> issueDto.setKee("issue3"));
+    db.rules().insertRule(ruleDto -> ruleDto.setUuid("rule3"));
+    db.issues().insertIssue(rule2, mainBranchComponent, file, issueDto -> issueDto.setKee("issue5").setStatus(Issue.STATUS_CLOSED));
+
+    Cursor<IssueDto> issueDtos = projectExportDao.scrollIssueForExport(db.getSession(), "project-uuid");
+    Set<IssueDto> issuesSet = toSet(issueDtos);
+
+    assertThat(issuesSet)
+      .hasSize(1)
+      .extracting("kee")
+      .containsOnly("issue1");
+
+  }
+
+  private RuleDto insertRule(String ruleName, boolean isExternal, boolean isAdHoc) {
+    return insertRule(ruleName, isExternal, isAdHoc, RuleStatus.READY);
+  }
+
+  private RuleDto insertRule(String ruleName, boolean isExternal, boolean isAdHoc, RuleStatus ruleStatus) {
+    RuleKey ruleKey = RuleKey.of("plugin1", ruleName);
+    db.rules().insertIssueRule(ProjectExportDaoIT.initRuleConsumer(ruleKey, isExternal, isAdHoc, ruleStatus));
+    return db.getDbClient().ruleDao().selectByKey(db.getSession(), ruleKey)
+      .orElseThrow(() -> new RuntimeException("insertAdHocRule failed"));
+  }
+
+  private static Consumer<RuleDto> initRuleConsumer(RuleKey ruleKey, boolean isExternal, boolean isAdHoc, RuleStatus ruleStatus) {
+    return rule -> {
+      rule
+        .setName(ruleKey.rule())
+        .setIsExternal(isExternal)
+        .setIsAdHoc(isAdHoc)
+        .setRuleKey(ruleKey)
+        .setPluginKey("pluginKey" + RandomStringUtils.randomAlphanumeric(10))
+        .setStatus(ruleStatus);
+      if (isAdHoc) {
+        rule.setAdHocName("ad_hoc_rule" + RandomStringUtils.randomAlphabetic(10))
+          .setAdHocType(RuleType.VULNERABILITY)
+          .setAdHocSeverity(Severity.CRITICAL)
+          .setAdHocDescription("ad hoc description: " + RandomStringUtils.randomAlphanumeric(100));
+      }
+    };
+  }
+
+  private static <T> Set<T> toSet(Cursor<T> ruleDtos) {
+    Iterator<T> ruleIterator = ruleDtos.iterator();
+    return Stream.generate(() -> null)
+      .takeWhile(x -> ruleIterator.hasNext())
+      .map(n -> ruleIterator.next())
+      .collect(Collectors.toSet());
+  }
+
+}
index cd454bd0d6446c31c1db22dd1a0326adffb60528..9186324b27ad556ee176cda0028f9c5ac17fc41f 100644 (file)
@@ -60,6 +60,7 @@ import org.sonar.db.plugin.PluginDao;
 import org.sonar.db.portfolio.PortfolioDao;
 import org.sonar.db.project.ProjectBadgeTokenDao;
 import org.sonar.db.project.ProjectDao;
+import org.sonar.db.project.ProjectExportDao;
 import org.sonar.db.property.InternalComponentPropertiesDao;
 import org.sonar.db.property.InternalPropertiesDao;
 import org.sonar.db.property.PropertiesDao;
@@ -153,6 +154,7 @@ public class DaoModule extends Module {
     PluginDao.class,
     ProjectDao.class,
     ProjectBadgeTokenDao.class,
+    ProjectExportDao.class,
     PortfolioDao.class,
     ProjectLinkDao.class,
     ProjectQgateAssociationDao.class,
index f4f30d4e40652c6af7fea2c9c10137ebb9b8afde..f9a93c4e0ba7f138b85573899edbde80f909de4c 100644 (file)
@@ -60,6 +60,7 @@ import org.sonar.db.plugin.PluginDao;
 import org.sonar.db.portfolio.PortfolioDao;
 import org.sonar.db.project.ProjectBadgeTokenDao;
 import org.sonar.db.project.ProjectDao;
+import org.sonar.db.project.ProjectExportDao;
 import org.sonar.db.property.InternalComponentPropertiesDao;
 import org.sonar.db.property.InternalPropertiesDao;
 import org.sonar.db.property.PropertiesDao;
@@ -191,6 +192,7 @@ public class DbClient {
   private final GithubOrganizationGroupDao githubOrganizationGroupDao;
   private final GithubPermissionsMappingDao githubPermissionsMappingDao;
   private final RuleChangeDao ruleChangeDao;
+  private final ProjectExportDao projectExportDao;
 
   public DbClient(Database database, MyBatis myBatis, DBSessions dbSessions, Dao... daos) {
     this.database = database;
@@ -282,6 +284,7 @@ public class DbClient {
     reportSubscriptionDao = getDao(map, ReportSubscriptionDao.class);
     anticipatedTransitionDao = getDao(map, AnticipatedTransitionDao.class);
     ruleChangeDao = getDao(map, RuleChangeDao.class);
+    projectExportDao = getDao(map, ProjectExportDao.class);
   }
 
   public DbSession openSession(boolean batch) {
@@ -625,5 +628,9 @@ public class DbClient {
   public RuleChangeDao ruleChangeDao() {
     return ruleChangeDao;
   }
+
+  public ProjectExportDao projectExportDao() {
+    return projectExportDao;
+  }
 }
 
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectExportDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectExportDao.java
new file mode 100644 (file)
index 0000000..3e6aa5c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.project;
+
+import java.util.List;
+import org.apache.ibatis.cursor.Cursor;
+import org.sonar.db.Dao;
+import org.sonar.db.DbSession;
+import org.sonar.db.component.BranchDto;
+import org.sonar.db.component.ProjectLinkDto;
+import org.sonar.db.issue.IssueDto;
+import org.sonar.db.newcodeperiod.NewCodePeriodDto;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.db.rule.RuleDto;
+
+public class ProjectExportDao implements Dao {
+
+  public List<BranchDto> selectBranchesForExport(DbSession dbSession, String projectUuid) {
+    return mapper(dbSession).selectBranchesForExport(projectUuid);
+  }
+
+  public List<PropertyDto> selectPropertiesForExport(DbSession dbSession, String projectUuid) {
+    return mapper(dbSession).selectPropertiesForExport(projectUuid);
+  }
+
+  public List<ProjectLinkDto> selectLinksForExport(DbSession dbSession, String projectUuid) {
+    return mapper(dbSession).selectLinksForExport(projectUuid);
+  }
+
+  public List<NewCodePeriodDto> selectNewCodePeriodsForExport(DbSession dbSession, String projectUuid) {
+    return mapper(dbSession).selectNewCodePeriodsForExport(projectUuid);
+  }
+
+  public Cursor<RuleDto> scrollAdhocRulesForExport(DbSession dbSession, String projectUuid) {
+    return mapper(dbSession).scrollAdhocRulesForExport(projectUuid);
+  }
+
+  public Cursor<IssueDto> scrollIssueForExport(DbSession dbSession, String projectUuid) {
+    return mapper(dbSession).scrollIssueForExport(projectUuid);
+  }
+
+  private static ProjectExportMapper mapper(DbSession session) {
+    return session.getMapper(ProjectExportMapper.class);
+  }
+
+}