]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-18872 improve total ncloc computation 10.0.0.68432
authorPierre <pierre.guillot@sonarsource.com>
Tue, 28 Mar 2023 08:16:41 +0000 (10:16 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 30 Mar 2023 20:03:08 +0000 (20:03 +0000)
23 files changed:
server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/ProjectNclocComputationStepIT.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ProjectNclocComputationStep.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java
server/sonar-db-dao/src/it/java/org/sonar/db/measure/LiveMeasureDaoIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java
server/sonar-db-dao/src/main/java/org/sonar/db/measure/LiveMeasureDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/measure/LiveMeasureMapper.java
server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/measure/LiveMeasureMapper.xml
server/sonar-db-dao/src/main/resources/org/sonar/db/project/ProjectMapper.xml
server/sonar-db-dao/src/schema/schema-sq.ddl
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v100/AddNclocToProjects.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v100/DbVersion100.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v100/PopulateNclocForForProjects.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v100/AddNclocToProjectsTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v100/PopulateNclocForForProjectsTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v100/AddNclocToProjectsTest/schema.sql [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v100/PopulateNclocForForProjectsTest/schema.sql [new file with mode: 0644]
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/StatisticsSupport.java
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/StatisticsSupportTest.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/ui/ws/MarketplaceActionIT.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/ws/MarketplaceAction.java

diff --git a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/ProjectNclocComputationStepIT.java b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/ProjectNclocComputationStepIT.java
new file mode 100644 (file)
index 0000000..38c925f
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.ce.task.projectanalysis.step;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
+import org.sonar.ce.task.step.TestComputationStepContext;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.BranchType;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.metric.MetricDto;
+import org.sonar.server.project.Project;
+
+import static java.util.Collections.emptyList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.measures.Metric.ValueType.INT;
+
+public class ProjectNclocComputationStepIT {
+  @Rule
+  public DbTester db = DbTester.create();
+  private final DbClient dbClient = db.getDbClient();
+
+  @Rule
+  public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule();
+
+  private final ProjectNclocComputationStep step = new ProjectNclocComputationStep(analysisMetadataHolder, dbClient);
+
+  @Test
+  public void test_computing_branch_ncloc() {
+    MetricDto ncloc = db.measures().insertMetric(m -> m.setKey("ncloc").setValueType(INT.toString()));
+    ComponentDto project = db.components().insertPublicProject();
+    ComponentDto branch1 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH));
+    db.measures().insertLiveMeasure(branch1, ncloc, m -> m.setValue(200d));
+    ComponentDto branch2 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH));
+    db.measures().insertLiveMeasure(branch2, ncloc, m -> m.setValue(10d));
+    analysisMetadataHolder.setProject(new Project(project.uuid(), project.getKey(), project.name(), project.description(), emptyList()));
+    step.execute(TestComputationStepContext.TestStatistics::new);
+
+    assertThat(dbClient.projectDao().getNclocSum(db.getSession())).isEqualTo(200L);
+  }
+
+  @Test
+  public void description_is_not_missing() {
+    assertThat(step.getDescription()).isNotBlank();
+  }
+}
\ No newline at end of file
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ProjectNclocComputationStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ProjectNclocComputationStep.java
new file mode 100644 (file)
index 0000000..c2cc101
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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.ce.task.projectanalysis.step;
+
+import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
+import org.sonar.ce.task.step.ComputationStep;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+
+public class ProjectNclocComputationStep implements ComputationStep {
+
+  private final AnalysisMetadataHolder analysisMetadataHolder;
+  private final DbClient dbClient;
+
+  public ProjectNclocComputationStep(AnalysisMetadataHolder analysisMetadataHolder, DbClient dbClient) {
+    this.analysisMetadataHolder = analysisMetadataHolder;
+    this.dbClient = dbClient;
+  }
+
+  @Override
+  public void execute(Context context) {
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      String projectUuid = analysisMetadataHolder.getProject().getUuid();
+      long maxncloc = dbClient.liveMeasureDao().sumNclocOfBiggestBranchForProject(dbSession, projectUuid);
+      dbClient.projectDao().updateNcloc(dbSession, projectUuid, maxncloc);
+      dbSession.commit();
+    }
+  }
+
+  @Override
+  public String getDescription() {
+    return "Compute total Project ncloc";
+  }
+}
index 8267f5a216a959bc171f2dbc8bc3b7037302145d..e93279055b4dc38b6e2940de6464bde9c86f94b8 100644 (file)
@@ -110,6 +110,7 @@ public class ReportComputationSteps extends AbstractComputationSteps {
     PurgeDatastoresStep.class,
     IndexAnalysisStep.class,
     UpdateNeedIssueSyncStep.class,
+    ProjectNclocComputationStep.class,
     PersistPushEventsStep.class,
 
     // notifications are sent at the end, so that webapp displays up-to-date information
index f63a7f5ef1f083cf778ec12422c0daeae1612b08..e519befcad41644e1a29654d97bb91734439280f 100644 (file)
@@ -365,12 +365,9 @@ public class LiveMeasureDaoIT {
     db.measures().insertLiveMeasure(projectWithLinesButNoLoc, lines, m -> m.setValue(365d));
     db.measures().insertLiveMeasure(projectWithLinesButNoLoc, ncloc, m -> m.setValue(0d));
 
-    SumNclocDbQuery query = SumNclocDbQuery.builder()
-      .setOnlyPrivateProjects(false)
-      .build();
-    long result = underTest.sumNclocOfBiggestBranch(db.getSession(), query);
-
-    assertThat(result).isEqualTo(10L + 200L);
+    assertThat(underTest.sumNclocOfBiggestBranchForProject(db.getSession(), simpleProject.uuid())).isEqualTo(10L);
+    assertThat(underTest.sumNclocOfBiggestBranchForProject(db.getSession(), projectWithBiggerBranch.uuid())).isEqualTo(200L);
+    assertThat(underTest.sumNclocOfBiggestBranchForProject(db.getSession(), projectWithLinesButNoLoc.uuid())).isZero();
   }
 
   @Test
@@ -411,40 +408,11 @@ public class LiveMeasureDaoIT {
   public void countNcloc_empty() {
     db.measures().insertMetric(m -> m.setKey("ncloc").setValueType(INT.toString()));
     db.measures().insertMetric(m -> m.setKey("lines").setValueType(INT.toString()));
-    SumNclocDbQuery query = SumNclocDbQuery.builder()
-      .setOnlyPrivateProjects(false)
-      .build();
-    long result = underTest.sumNclocOfBiggestBranch(db.getSession(), query);
+    long result = underTest.sumNclocOfBiggestBranchForProject(db.getSession(), "non-existing-project-uuid");
 
     assertThat(result).isZero();
   }
 
-  @Test
-  public void countNcloc_and_exclude_project() {
-    MetricDto ncloc = db.measures().insertMetric(m -> m.setKey("ncloc").setValueType(INT.toString()));
-
-    ComponentDto simpleProject = db.components().insertPublicProject();
-    db.measures().insertLiveMeasure(simpleProject, ncloc, m -> m.setValue(10d));
-
-    ComponentDto projectWithBiggerBranch = db.components().insertPublicProject();
-    ComponentDto bigBranch = db.components().insertProjectBranch(projectWithBiggerBranch, b -> b.setBranchType(BranchType.BRANCH));
-    db.measures().insertLiveMeasure(projectWithBiggerBranch, ncloc, m -> m.setValue(100d));
-    db.measures().insertLiveMeasure(bigBranch, ncloc, m -> m.setValue(200d));
-
-    ComponentDto projectToExclude = db.components().insertPublicProject();
-    ComponentDto projectToExcludeBranch = db.components().insertProjectBranch(projectToExclude, b -> b.setBranchType(BranchType.BRANCH));
-    db.measures().insertLiveMeasure(projectToExclude, ncloc, m -> m.setValue(300d));
-    db.measures().insertLiveMeasure(projectToExcludeBranch, ncloc, m -> m.setValue(400d));
-
-    SumNclocDbQuery query = SumNclocDbQuery.builder()
-      .setProjectUuidToExclude(projectToExclude.uuid())
-      .setOnlyPrivateProjects(false)
-      .build();
-    long result = underTest.sumNclocOfBiggestBranch(db.getSession(), query);
-
-    assertThat(result).isEqualTo(10L + 200L);
-  }
-
   @Test
   public void insert_data() {
     byte[] data = "text_value".getBytes(StandardCharsets.UTF_8);
index 7364e759ef65d4c76a32a9da6dbe72279c88048a..05958a69359a7d778a89f98e902d6f4c2f85f975 100644 (file)
@@ -31,6 +31,7 @@ import java.util.function.Consumer;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 import javax.annotation.Nullable;
+import org.assertj.core.api.Assertions;
 import org.assertj.core.groups.Tuple;
 import org.junit.Rule;
 import org.junit.Test;
@@ -279,6 +280,31 @@ public class ProjectDaoIT {
       .containsExactlyInAnyOrderElementsOf(extractComponentUuids(projects));
   }
 
+  @Test
+  public void update_ncloc_should_update_project() {
+    ComponentDto project = db.components().insertPublicProject();
+
+    projectDao.updateNcloc(db.getSession(), project.uuid(), 10L);
+
+    Assertions.assertThat(projectDao.getNclocSum(db.getSession())).isEqualTo(10L);
+  }
+
+  @Test
+  public void getNcloc_sum_compute_correctly_sum_of_projects() {
+    projectDao.updateNcloc(db.getSession(), db.components().insertPublicProject().uuid(), 1L);
+    projectDao.updateNcloc(db.getSession(), db.components().insertPublicProject().uuid(), 20L);
+    projectDao.updateNcloc(db.getSession(), db.components().insertPublicProject().uuid(), 100L);
+    Assertions.assertThat(projectDao.getNclocSum(db.getSession())).isEqualTo(121L);
+  }
+
+  @Test
+  public void getNcloc_sum_compute_correctly_sum_of_projects_while_excluding_project() {
+    projectDao.updateNcloc(db.getSession(), db.components().insertPublicProject().uuid(), 1L);
+    projectDao.updateNcloc(db.getSession(), db.components().insertPublicProject().uuid(), 20L);
+    ComponentDto project3 = db.components().insertPublicProject();
+    projectDao.updateNcloc(db.getSession(), project3.uuid(), 100L);
+    Assertions.assertThat(projectDao.getNclocSum(db.getSession(), project3.uuid())).isEqualTo(21L);
+  }
   @Test
   public void selectAllProjectUuids_shouldOnlyReturnProjectWithTRKQualifier() {
     ComponentDto application = db.components().insertPrivateApplication();
index 9f04ff22b5e6b0da806ba6f4a84dcefcf9740bfd..9dcfb0e72de9806e011db25c9563c6cd07dfc78b 100644 (file)
@@ -94,14 +94,8 @@ public class LiveMeasureDao implements Dao {
     mapper(dbSession).selectTreeByQuery(query, baseComponent.uuid(), query.getUuidPath(baseComponent), resultHandler);
   }
 
-  /**
-   * Example:
-   * If Main Branch = 0 LOCs (provisioned but never analyzed) and the "largest branch" is 120 LOCs, I'm expecting to consider the value 120.
-   * If Main Branch = 100 LOCs and the "largest branch" is 120 LOCs, I'm expecting to consider the value 120.
-   * If Main Branch = 100 LOCs and the "largest branch" is 80 LOCs, I'm expecting to consider the value 100.
-   */
-  public long sumNclocOfBiggestBranch(DbSession dbSession, SumNclocDbQuery dbQuery) {
-    Long ncloc = mapper(dbSession).sumNclocOfBiggestBranch(NCLOC_KEY, dbQuery.getOnlyPrivateProjects(), dbQuery.getProjectUuidToExclude());
+  public long sumNclocOfBiggestBranchForProject(DbSession dbSession, String projectUuid){
+    Long ncloc = mapper(dbSession).sumNclocOfBiggestBranchForProject(projectUuid, NCLOC_KEY);
     return ncloc == null ? 0L : ncloc;
   }
 
index e93f7742a246ff315aed69169902067752b43e9f..9b84c0c3cee3c7146f94610403621250cfb635b8 100644 (file)
@@ -21,7 +21,7 @@ package org.sonar.db.measure;
 
 import java.util.Collection;
 import java.util.List;
-import javax.annotation.Nullable;
+import javax.annotation.CheckForNull;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.session.ResultHandler;
 
@@ -57,10 +57,8 @@ public interface LiveMeasureMapper {
     @Param("baseUuidPath") String baseUuidPath,
     ResultHandler<LiveMeasureDto> resultHandler);
 
-  Long sumNclocOfBiggestBranch(
-    @Param("ncloc") String nclocKey,
-    @Param("private") Boolean privateProject,
-    @Nullable @Param("projectUuidToExclude") String projectUuidToExclude);
+  @CheckForNull
+  Long sumNclocOfBiggestBranchForProject(@Param("projectUuid") String projectUuid, @Param("ncloc") String nclocKey);
 
   List<LargestBranchNclocDto> getLargestBranchNclocPerProject(@Param("nclocUuid") String nclocUuid);
 
index 30f3796acb8126196c93284278a374314c2e5c99..11f5c17c37f0f8a3eeab557800579ba5e4e3ca08 100644 (file)
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
+import javax.annotation.Nullable;
 import org.sonar.api.utils.System2;
 import org.sonar.db.Dao;
 import org.sonar.db.DbSession;
@@ -126,4 +127,16 @@ public class ProjectDao implements Dao {
     Set<String> languageFilters = Set.of(language + "=%", "%;" + language + "=%");
     return mapper(session).selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(languageFilters);
   }
+
+  public void updateNcloc(DbSession dbSession, String projectUuid, long ncloc) {
+    mapper(dbSession).updateNcloc(projectUuid, ncloc);
+  }
+
+  public long getNclocSum(DbSession dbSession) {
+    return getNclocSum(dbSession, null);
+  }
+
+  public long getNclocSum(DbSession dbSession, @Nullable String projectUuidToExclude) {
+    return Optional.ofNullable(mapper(dbSession).getNclocSum(projectUuidToExclude)).orElse(0L);
+  }
 }
index 58e635cd016c905919eacfe08a7601553c168fee..3253c1578b3d7a96161df3b7a298f3457db306ea 100644 (file)
@@ -23,6 +23,7 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
 import org.apache.ibatis.annotations.Param;
 
 public interface ProjectMapper {
@@ -62,4 +63,10 @@ public interface ProjectMapper {
   List<String> selectAllProjectUuids();
 
   Set<String> selectProjectUuidsAssociatedToDefaultQualityProfileByLanguage(@Param("languageFilters") Set<String> languageFilters);
+
+  void updateNcloc(@Param("projectUuid") String projectUuid, @Param("ncloc") long ncloc);
+
+  @CheckForNull
+  Long getNclocSum(@Nullable @Param("projectUuidToExclude") String projectUuidToExclude);
+
 }
index c4d49599fc1c389da9f241bd8c4a45143cbd3962..1395671580d2678553d8ed0c2402d5eaa29b42be 100644 (file)
@@ -61,8 +61,8 @@
     and lm.component_uuid = #{componentUuid, jdbcType=VARCHAR}
   </select>
 
-  <select id="sumNclocOfBiggestBranch" parameterType="map" resultType="long">
-    select sum(sumncloc.maxncloc) from (
+  <select id="sumNclocOfBiggestBranchForProject" parameterType="map" resultType="long">
+    select sumncloc.maxncloc from (
       select b.project_uuid as projectUuid, max(lm.value) as maxncloc
       from live_measures lm
       inner join metrics m on m.uuid = lm.metric_uuid
       inner join projects p on p.uuid = b.project_uuid and p.qualifier = 'TRK'
       <where>
         m.name = #{ncloc, jdbcType=VARCHAR}
-        <if test="private">
-          and p.private=${_true}
-        </if>
-        <if test="projectUuidToExclude != null">
-          and b.project_uuid &lt;&gt; #{projectUuidToExclude,jdbcType=VARCHAR}
-        </if>
+        and b.project_uuid = #{projectUuid,jdbcType=VARCHAR}
       </where>
       group by b.project_uuid
     ) sumncloc
index 9f32c5a8520e182395ae0454d350be70a7798ab5..baae55a33f228c1e7fd6b105bb5d5ae0258a01da 100644 (file)
     uuid = #{uuid,jdbcType=VARCHAR}
   </update>
 
+
+  <update id="updateNcloc">
+    update projects set
+    ncloc = #{ncloc,jdbcType=BIGINT}
+    where
+    uuid = #{projectUuid,jdbcType=VARCHAR}
+  </update>
+
+  <select id="getNclocSum" parameterType="string" resultType="long">
+    select sum(ncloc) from projects where qualifier = 'TRK'
+    <if test="projectUuidToExclude != null">
+      and uuid &lt;&gt; #{projectUuidToExclude,jdbcType=VARCHAR}
+    </if>
+  </select>
+
 </mapper>
index 0662a2a6a890b03738438942612bd0693fee1226..f3b228c4440443690eda1203c20e2fbb6f181840 100644 (file)
@@ -716,7 +716,8 @@ CREATE TABLE "PROJECTS"(
     "PRIVATE" BOOLEAN NOT NULL,
     "TAGS" CHARACTER VARYING(500),
     "CREATED_AT" BIGINT,
-    "UPDATED_AT" BIGINT NOT NULL
+    "UPDATED_AT" BIGINT NOT NULL,
+    "NCLOC" BIGINT
 );
 ALTER TABLE "PROJECTS" ADD CONSTRAINT "PK_NEW_PROJECTS" PRIMARY KEY("UUID");
 CREATE UNIQUE INDEX "UNIQ_PROJECTS_KEE" ON "PROJECTS"("KEE" NULLS FIRST);
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v100/AddNclocToProjects.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v100/AddNclocToProjects.java
new file mode 100644 (file)
index 0000000..c39dc36
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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.server.platform.db.migration.version.v100;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.db.DatabaseUtils;
+import org.sonar.server.platform.db.migration.def.BigIntegerColumnDef;
+import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class AddNclocToProjects extends DdlChange {
+
+  public static final String PROJECT_TABLE_NAME = "projects";
+  public static final String NCLOC_COLUMN_NAME = "ncloc";
+
+  public AddNclocToProjects(Database db) {
+    super(db);
+  }
+
+  @Override
+  public void execute(Context context) throws SQLException {
+    if (checkIfColumnExists()) {
+      return;
+    }
+    BigIntegerColumnDef columnDef = BigIntegerColumnDef.newBigIntegerColumnDefBuilder().setColumnName(NCLOC_COLUMN_NAME).setIsNullable(true).build();
+    String request = new AddColumnsBuilder(getDialect(), PROJECT_TABLE_NAME).addColumn(columnDef).build();
+    context.execute(request);
+  }
+
+  public boolean checkIfColumnExists() throws SQLException {
+    try (var connection = getDatabase().getDataSource().getConnection()) {
+      if (DatabaseUtils.tableColumnExists(connection, PROJECT_TABLE_NAME, NCLOC_COLUMN_NAME)) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
index 1217495bcc28344f8254dc6aad3aaeb85d5c80f8..ba6d6a3169f4edfb9c7119ca0416026f808ce520 100644 (file)
@@ -56,6 +56,8 @@ public class DbVersion100 implements DbVersion {
       .add(10_0_012, "Log a warning message if 'sonar.scim.enabled' is used", LogMessageIfSonarScimEnabledPresentProperty.class)
       .add(10_0_013, "Drop 'sonar.scim.enabled' property", DropSonarScimEnabledProperty.class)
       .add(10_0_014, "Drop any SCIM User provisioning, turning all users local", DropScimUserProvisioning.class)
+      .add(10_0_015, "Add ncloc to 'Projects' table", AddNclocToProjects.class)
+      .add(10_0_016, "Populate ncloc in 'Projects' table", PopulateNclocForForProjects.class)
     ;
   }
 }
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v100/PopulateNclocForForProjects.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v100/PopulateNclocForForProjects.java
new file mode 100644 (file)
index 0000000..ffb3fb0
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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.server.platform.db.migration.version.v100;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+
+public class PopulateNclocForForProjects extends DataChange {
+
+  private static final String SELECT_QUERY = """
+    SELECT b.project_uuid AS projectUuid, max(lm.value) AS maxncloc
+    FROM live_measures lm
+    INNER JOIN metrics m ON m.uuid = lm.metric_uuid
+    INNER JOIN project_branches b ON b.uuid = lm.component_uuid
+    INNER JOIN projects p on p.uuid = b.project_uuid and p.qualifier = 'TRK'
+    WHERE m.name  = 'ncloc'
+    GROUP BY b.project_uuid
+    """;
+
+  public PopulateNclocForForProjects(Database db) {
+    super(db);
+  }
+
+  @Override
+  protected void execute(Context context) throws SQLException {
+    MassUpdate massUpdate = context.prepareMassUpdate();
+    massUpdate.select(SELECT_QUERY);
+    massUpdate.update("update projects set ncloc = ? where uuid = ?");
+    massUpdate.execute((row, update) -> {
+      String uuid = row.getString(1);
+      Long ncloc = row.getLong(2);
+      update.setLong(1, ncloc);
+      update.setString(2, uuid);
+      return true;
+    });
+  }
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v100/AddNclocToProjectsTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v100/AddNclocToProjectsTest.java
new file mode 100644 (file)
index 0000000..c67930e
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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.server.platform.db.migration.version.v100;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class AddNclocToProjectsTest {
+
+  private static final String TABLE_NAME = "projects";
+  private static final String COLUMN_NAME = "ncloc";
+
+  @Rule
+  public final CoreDbTester db = CoreDbTester.createForSchema(AddNclocToProjectsTest.class, "schema.sql");
+  private final DdlChange underTest = new AddNclocToProjects(db.database());
+
+  @Test
+  public void add_column() throws SQLException {
+    db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+    db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+    underTest.execute();
+    db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, Types.BIGINT, null, true);
+  }
+
+  @Test
+  public void migration_is_reentrant() throws SQLException {
+    db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+    underTest.execute();
+    underTest.execute();
+    db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, Types.BIGINT, null, true);
+  }
+
+}
\ No newline at end of file
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v100/PopulateNclocForForProjectsTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v100/PopulateNclocForForProjectsTest.java
new file mode 100644 (file)
index 0000000..66527f7
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * 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.server.platform.db.migration.version.v100;
+
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.core.util.UuidFactoryFast;
+import org.sonar.db.CoreDbTester;
+import org.sonar.server.platform.db.migration.step.DataChange;
+
+import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class PopulateNclocForForProjectsTest {
+
+  private final UuidFactory uuidFactory = UuidFactoryFast.getInstance();
+
+  @Rule
+  public CoreDbTester db = CoreDbTester.createForSchema(PopulateNclocForForProjectsTest.class, "schema.sql");
+
+  private final DataChange underTest = new PopulateNclocForForProjects(db.database());
+
+  @Test
+  public void migration_populates_ncloc_for_projects() throws SQLException {
+    Map<String, Long> expectedNclocByProjectUuid = populateData();
+    underTest.execute();
+    verifyNclocCorrectlyPopulatedForProjects(expectedNclocByProjectUuid);
+  }
+
+  @Test
+  public void migration_should_be_reentrant() throws SQLException {
+    Map<String, Long> expectedNclocByProjectUuid = populateData();
+    underTest.execute();
+    // re-entrant
+    underTest.execute();
+    verifyNclocCorrectlyPopulatedForProjects(expectedNclocByProjectUuid);
+  }
+
+  private Map<String, Long> populateData() {
+    String nclocMetricUuid = insertMetric("ncloc");
+
+    String projectUuid1 = insertProject();
+    String project1Branch1 = insertProjectBranch(projectUuid1);
+    String project1Branch2 = insertProjectBranch(projectUuid1);
+
+    long project1maxNcloc = 100;
+    insertLiveMeasure(nclocMetricUuid, projectUuid1, project1Branch1, 80L);
+    insertLiveMeasure(nclocMetricUuid, projectUuid1, project1Branch2, project1maxNcloc);
+
+    String otherMetricUuid = insertMetric("other");
+    insertLiveMeasure(otherMetricUuid, projectUuid1, project1Branch1, 5000L);
+    insertLiveMeasure(otherMetricUuid, projectUuid1, project1Branch2, 6000L);
+
+    String projectUuid2 = insertProject();
+    String project2Branch1 = insertProjectBranch(projectUuid2);
+    String project2Branch2 = insertProjectBranch(projectUuid2);
+    String project2Branch3 = insertProjectBranch(projectUuid2);
+
+    long project2maxNcloc = 60;
+    insertLiveMeasure(nclocMetricUuid, projectUuid2, project2Branch1, 20L);
+    insertLiveMeasure(nclocMetricUuid, projectUuid2, project2Branch2, 50L);
+    insertLiveMeasure(nclocMetricUuid, projectUuid2, project2Branch3, project2maxNcloc);
+
+    return Map.of(projectUuid1, project1maxNcloc, projectUuid2, project2maxNcloc);
+  }
+
+  private void verifyNclocCorrectlyPopulatedForProjects(Map<String, Long> expectedNclocByProjectUuid) {
+    for (Map.Entry<String, Long> entry : expectedNclocByProjectUuid.entrySet()) {
+      String query = String.format("select ncloc from projects where uuid='%s'", entry.getKey());
+      Long nclocFromProject = (Long) db.selectFirst(query).get("NCLOC");
+      assertThat(nclocFromProject).isEqualTo(entry.getValue());
+    }
+  }
+
+  private String insertMetric(String name) {
+    Map<String, Object> map = new HashMap<>();
+    String uuid = uuidFactory.create();
+    map.put("UUID", uuid);
+    map.put("NAME", name);
+    db.executeInsert("metrics", map);
+    return uuid;
+  }
+
+  private String insertProject() {
+    Map<String, Object> map = new HashMap<>();
+    String uuid = uuidFactory.create();
+    map.put("UUID", uuid);
+    map.put("KEE", randomAlphabetic(20));
+    map.put("QUALIFIER", "TRK");
+    map.put("PRIVATE", true);
+    map.put("UPDATED_AT", System.currentTimeMillis());
+    db.executeInsert("projects", map);
+    return uuid;
+  }
+
+  private String insertProjectBranch(String projectUuid) {
+    Map<String, Object> map = new HashMap<>();
+    String uuid = uuidFactory.create();
+    map.put("UUID", uuid);
+    map.put("PROJECT_UUID", projectUuid);
+    map.put("KEE", randomAlphabetic(20));
+    map.put("BRANCH_TYPE", "PULL_REQUEST");
+    map.put("UPDATED_AT", System.currentTimeMillis());
+    map.put("CREATED_AT", System.currentTimeMillis());
+    map.put("NEED_ISSUE_SYNC", false);
+    db.executeInsert("project_branches", map);
+    return uuid;
+  }
+
+  private void insertLiveMeasure(String metricUuid, String projectUuid, String componentUuid, Long value) {
+    Map<String, Object> map = new HashMap<>();
+    String uuid = uuidFactory.create();
+    map.put("UUID", uuid);
+    map.put("PROJECT_UUID", projectUuid);
+    map.put("COMPONENT_UUID", componentUuid);
+    map.put("METRIC_UUID", metricUuid);
+    map.put("VALUE", value);
+    map.put("UPDATED_AT", System.currentTimeMillis());
+    map.put("CREATED_AT", System.currentTimeMillis());
+    db.executeInsert("live_measures", map);
+  }
+
+}
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v100/AddNclocToProjectsTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v100/AddNclocToProjectsTest/schema.sql
new file mode 100644 (file)
index 0000000..5cc62fc
--- /dev/null
@@ -0,0 +1,15 @@
+
+CREATE TABLE "PROJECTS"(
+    "UUID" CHARACTER VARYING(40) NOT NULL,
+    "KEE" CHARACTER VARYING(400) NOT NULL,
+    "QUALIFIER" CHARACTER VARYING(10) NOT NULL,
+    "NAME" CHARACTER VARYING(2000),
+    "DESCRIPTION" CHARACTER VARYING(2000),
+    "PRIVATE" BOOLEAN NOT NULL,
+    "TAGS" CHARACTER VARYING(500),
+    "CREATED_AT" BIGINT,
+    "UPDATED_AT" BIGINT NOT NULL
+);
+ALTER TABLE "PROJECTS" ADD CONSTRAINT "PK_NEW_PROJECTS" PRIMARY KEY("UUID");
+CREATE UNIQUE INDEX "UNIQ_PROJECTS_KEE" ON "PROJECTS"("KEE" NULLS FIRST);
+CREATE INDEX "IDX_QUALIFIER" ON "PROJECTS"("QUALIFIER" NULLS FIRST);
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v100/PopulateNclocForForProjectsTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v100/PopulateNclocForForProjectsTest/schema.sql
new file mode 100644 (file)
index 0000000..f69434e
--- /dev/null
@@ -0,0 +1,67 @@
+CREATE TABLE "PROJECTS"(
+    "UUID" CHARACTER VARYING(40) NOT NULL,
+    "KEE" CHARACTER VARYING(400) NOT NULL,
+    "QUALIFIER" CHARACTER VARYING(10) NOT NULL,
+    "NAME" CHARACTER VARYING(2000),
+    "DESCRIPTION" CHARACTER VARYING(2000),
+    "PRIVATE" BOOLEAN NOT NULL,
+    "TAGS" CHARACTER VARYING(500),
+    "CREATED_AT" BIGINT,
+    "UPDATED_AT" BIGINT NOT NULL,
+    "NCLOC" BIGINT
+);
+ALTER TABLE "PROJECTS" ADD CONSTRAINT "PK_NEW_PROJECTS" PRIMARY KEY("UUID");
+CREATE UNIQUE INDEX "UNIQ_PROJECTS_KEE" ON "PROJECTS"("KEE" NULLS FIRST);
+CREATE INDEX "IDX_QUALIFIER" ON "PROJECTS"("QUALIFIER" NULLS FIRST);
+
+CREATE TABLE "PROJECT_BRANCHES"(
+    "UUID" CHARACTER VARYING(50) NOT NULL,
+    "PROJECT_UUID" CHARACTER VARYING(50) NOT NULL,
+    "KEE" CHARACTER VARYING(255) NOT NULL,
+    "BRANCH_TYPE" CHARACTER VARYING(12) NOT NULL,
+    "MERGE_BRANCH_UUID" CHARACTER VARYING(50),
+    "PULL_REQUEST_BINARY" BINARY LARGE OBJECT,
+    "MANUAL_BASELINE_ANALYSIS_UUID" CHARACTER VARYING(40),
+    "CREATED_AT" BIGINT NOT NULL,
+    "UPDATED_AT" BIGINT NOT NULL,
+    "EXCLUDE_FROM_PURGE" BOOLEAN DEFAULT FALSE NOT NULL,
+    "NEED_ISSUE_SYNC" BOOLEAN NOT NULL
+);
+ALTER TABLE "PROJECT_BRANCHES" ADD CONSTRAINT "PK_PROJECT_BRANCHES" PRIMARY KEY("UUID");
+CREATE UNIQUE INDEX "UNIQ_PROJECT_BRANCHES" ON "PROJECT_BRANCHES"("BRANCH_TYPE" NULLS FIRST, "PROJECT_UUID" NULLS FIRST, "KEE" NULLS FIRST);
+
+CREATE TABLE "LIVE_MEASURES"(
+    "UUID" CHARACTER VARYING(40) NOT NULL,
+    "PROJECT_UUID" CHARACTER VARYING(50) NOT NULL,
+    "COMPONENT_UUID" CHARACTER VARYING(50) NOT NULL,
+    "METRIC_UUID" CHARACTER VARYING(40) NOT NULL,
+    "VALUE" DOUBLE PRECISION,
+    "TEXT_VALUE" CHARACTER VARYING(4000),
+    "MEASURE_DATA" BINARY LARGE OBJECT,
+    "UPDATE_MARKER" CHARACTER VARYING(40),
+    "CREATED_AT" BIGINT NOT NULL,
+    "UPDATED_AT" BIGINT NOT NULL
+);
+ALTER TABLE "LIVE_MEASURES" ADD CONSTRAINT "PK_LIVE_MEASURES" PRIMARY KEY("UUID");
+CREATE INDEX "LIVE_MEASURES_PROJECT" ON "LIVE_MEASURES"("PROJECT_UUID" NULLS FIRST);
+CREATE UNIQUE INDEX "LIVE_MEASURES_COMPONENT" ON "LIVE_MEASURES"("COMPONENT_UUID" NULLS FIRST, "METRIC_UUID" NULLS FIRST);
+
+CREATE TABLE "METRICS"(
+    "UUID" CHARACTER VARYING(40) NOT NULL,
+    "NAME" CHARACTER VARYING(64) NOT NULL,
+    "DESCRIPTION" CHARACTER VARYING(255),
+    "DIRECTION" INTEGER DEFAULT 0 NOT NULL,
+    "DOMAIN" CHARACTER VARYING(64),
+    "SHORT_NAME" CHARACTER VARYING(64),
+    "QUALITATIVE" BOOLEAN DEFAULT FALSE NOT NULL,
+    "VAL_TYPE" CHARACTER VARYING(8),
+    "ENABLED" BOOLEAN DEFAULT TRUE,
+    "WORST_VALUE" DOUBLE PRECISION,
+    "BEST_VALUE" DOUBLE PRECISION,
+    "OPTIMIZED_BEST_VALUE" BOOLEAN,
+    "HIDDEN" BOOLEAN,
+    "DELETE_HISTORICAL_DATA" BOOLEAN,
+    "DECIMAL_SCALE" INTEGER
+);
+ALTER TABLE "METRICS" ADD CONSTRAINT "PK_METRICS" PRIMARY KEY("UUID");
+CREATE UNIQUE INDEX "METRICS_UNIQUE_NAME" ON "METRICS"("NAME" NULLS FIRST);
index 29325634dce610ce03104b546337bd6684a5e7ff..4d8f07d5c0601825e116a9a55bf0ee490ac8e696 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.server.platform;
 
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
-import org.sonar.db.measure.SumNclocDbQuery;
 
 public class StatisticsSupport {
 
@@ -33,10 +32,7 @@ public class StatisticsSupport {
 
   public long getLinesOfCode(){
     try (DbSession dbSession = dbClient.openSession(false)) {
-      SumNclocDbQuery query = SumNclocDbQuery.builder()
-        .setOnlyPrivateProjects(false)
-        .build();
-      return dbClient.liveMeasureDao().sumNclocOfBiggestBranch(dbSession, query);
+      return dbClient.projectDao().getNclocSum(dbSession);
     }
   }
 }
index 872862a0699c4f6b2da00fb338346dbcc3d411ec..052ab11bbea924409a4be8e92c3cb2dfe79e8ba1 100644 (file)
@@ -22,7 +22,6 @@ package org.sonar.server.platform;
 import org.junit.Test;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
-import org.sonar.db.measure.SumNclocDbQuery;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
@@ -37,7 +36,7 @@ public class StatisticsSupportTest {
 
   @Test
   public void should_return_metric_from_liveMeasureDao() {
-    when(dbClient.liveMeasureDao().sumNclocOfBiggestBranch(any(DbSession.class), any(SumNclocDbQuery.class))).thenReturn(1800999L);
+    when(dbClient.projectDao().getNclocSum(any(DbSession.class))).thenReturn(1800999L);
 
     long linesOfCode = statisticsSupport.getLinesOfCode();
 
index 2b6f01fdd68000c6449512ca84c4352f3e46ab2d..001e1d35889a5004975e548657879684c33b2266 100644 (file)
@@ -28,7 +28,6 @@ import org.sonar.api.server.ws.WebService;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
-import org.sonar.db.metric.MetricDto;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.UnauthorizedException;
 import org.sonar.server.tester.UserSessionRule;
@@ -40,8 +39,6 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
-import static org.sonar.api.measures.Metric.ValueType.INT;
 import static org.sonar.test.JsonAssert.assertJson;
 
 @RunWith(DataProviderRunner.class)
@@ -120,7 +117,7 @@ public class MarketplaceActionIT {
 
   private void setNcloc(double ncloc) {
     ComponentDto project = db.components().insertPublicProject();
-    MetricDto nclocMetric = db.measures().insertMetric(m -> m.setValueType(INT.toString()).setKey(NCLOC_KEY));
-    db.measures().insertLiveMeasure(project, nclocMetric, m -> m.setValue(ncloc));
+    db.getDbClient().projectDao().updateNcloc(db.getSession(), project.uuid(), (long) ncloc);
+    db.commit();
   }
 }
index 7c4f7b3b8bbfca0d7b7b74a7b54fd8b36581a035..918f8a49b47c7de91d03bb4179e5492f788c036a 100644 (file)
@@ -25,7 +25,6 @@ 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.measure.SumNclocDbQuery;
 import org.sonar.server.user.UserSession;
 import org.sonarqube.ws.Navigation;
 
@@ -68,10 +67,7 @@ public class MarketplaceAction implements NavigationWsAction {
 
   private long computeNcloc() {
     try (DbSession dbSession = dbClient.openSession(false)) {
-      SumNclocDbQuery query = SumNclocDbQuery.builder()
-        .setOnlyPrivateProjects(false)
-        .build();
-      return dbClient.liveMeasureDao().sumNclocOfBiggestBranch(dbSession, query);
+      return dbClient.projectDao().getNclocSum(dbSession);
     }
   }
 }