]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13915 - ncloc_language_distribution is taken from biggest branch
authorBelen Pruvost <belen.pruvost@sonarsource.com>
Wed, 15 Jun 2022 10:28:31 +0000 (12:28 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 15 Jun 2022 20:03:03 +0000 (20:03 +0000)
server/sonar-db-dao/src/main/java/org/sonar/db/measure/ProjectMeasuresIndexerIterator.java
server/sonar-db-dao/src/test/java/org/sonar/db/measure/ProjectMeasuresIndexerIteratorTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java

index 6261483715dff292030e0daa50ad6395160f1aec..37126bf775b8b0d835b317253496c37b90062a39 100644 (file)
@@ -61,8 +61,8 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea
     CoreMetrics.SECURITY_RATING_KEY,
     CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_KEY,
     CoreMetrics.SECURITY_REVIEW_RATING_KEY,
-    CoreMetrics.ALERT_STATUS_KEY,
     CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY,
+    CoreMetrics.ALERT_STATUS_KEY,
     CoreMetrics.NEW_SECURITY_RATING_KEY,
     CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_KEY,
     CoreMetrics.NEW_SECURITY_REVIEW_RATING_KEY,
@@ -85,16 +85,39 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea
     "AND m.name IN ({metricNames}) " +
     "AND (pm.value IS NOT NULL OR pm.variation IS NOT NULL OR pm.text_value IS NOT NULL) " +
     "AND m.enabled = ? ";
+
+  private static final String SQL_NCLOC_LANGUAGE_DISTRIBUTION = "SELECT m.name, pm.value, pm.variation, pm.text_value FROM live_measures pm " +
+    "INNER JOIN metrics m ON m.uuid = pm.metric_uuid " +
+    "WHERE pm.component_uuid = ? " +
+    "AND m.name = ? " +
+    "AND (pm.value IS NOT NULL OR pm.variation IS NOT NULL OR pm.text_value IS NOT NULL) " +
+    "AND m.enabled = ? ";
+
+  private static final String SQL_PROJECT_BRANCHES = "SELECT uuid FROM project_branches pb " +
+    "WHERE pb.project_uuid = ? ";
+
+  private static final String SQL_BIGGEST_NCLOC_VALUE = "SELECT max(lm.value) FROM metrics m " +
+    "INNER JOIN live_measures lm ON m.uuid = lm.metric_uuid " +
+    "WHERE lm.component_uuid IN ({projectBranches}) " +
+    "AND m.name = ? AND lm.value IS NOT NULL AND m.enabled = ? ";
+
+  private static final String SQL_BIGGEST_BRANCH = "SELECT lm.component_uuid FROM metrics m " +
+    "INNER JOIN live_measures lm ON m.uuid = lm.metric_uuid " +
+    "WHERE lm.component_uuid IN ({projectBranches}) " +
+    "AND m.name = ? AND lm.value = ? AND m.enabled = ? ";
+
   private static final boolean ENABLED = true;
   private static final int FIELD_METRIC_NAME = 1;
   private static final int FIELD_MEASURE_VALUE = 2;
   private static final int FIELD_MEASURE_VARIATION = 3;
   private static final int FIELD_MEASURE_TEXT_VALUE = 4;
 
+  private final DbSession dbSession;
   private final PreparedStatement measuresStatement;
   private final Iterator<Project> projects;
 
-  private ProjectMeasuresIndexerIterator(PreparedStatement measuresStatement, List<Project> projects) {
+  private ProjectMeasuresIndexerIterator(DbSession dbSession, PreparedStatement measuresStatement, List<Project> projects) {
+    this.dbSession = dbSession;
     this.measuresStatement = measuresStatement;
     this.projects = projects.iterator();
   }
@@ -102,13 +125,13 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea
   public static ProjectMeasuresIndexerIterator create(DbSession session, @Nullable String projectUuid) {
     List<Project> projects = selectProjects(session, projectUuid);
     PreparedStatement projectsStatement = createMeasuresStatement(session);
-    return new ProjectMeasuresIndexerIterator(projectsStatement, projects);
+    return new ProjectMeasuresIndexerIterator(session, projectsStatement, projects);
   }
 
   private static List<Project> selectProjects(DbSession session, @Nullable String projectUuid) {
     List<Project> projects = new ArrayList<>();
     try (PreparedStatement stmt = createProjectsStatement(session, projectUuid);
-      ResultSet rs = stmt.executeQuery()) {
+         ResultSet rs = stmt.executeQuery()) {
       while (rs.next()) {
         String uuid = rs.getString(1);
         String key = rs.getString(2);
@@ -146,7 +169,9 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea
 
   private static PreparedStatement createMeasuresStatement(DbSession session) {
     try {
-      String metricNameQuestionMarks = METRIC_KEYS.stream().map(x -> "?").collect(Collectors.joining(","));
+      String metricNameQuestionMarks = METRIC_KEYS.stream()
+        .filter(m -> !m.equals(NCLOC_LANGUAGE_DISTRIBUTION_KEY))
+        .map(x -> "?").collect(Collectors.joining(","));
       String sql = StringUtils.replace(SQL_MEASURES, "{metricNames}", metricNameQuestionMarks);
       return session.getConnection().prepareStatement(sql);
     } catch (SQLException e) {
@@ -169,14 +194,23 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea
     Measures measures = new Measures();
     ResultSet rs = null;
     try {
-      AtomicInteger index = new AtomicInteger(1);
-      measuresStatement.setString(index.getAndIncrement(), projectUuid);
-      METRIC_KEYS.forEach(DatabaseUtils.setStrings(measuresStatement, index::getAndIncrement));
-      measuresStatement.setBoolean(index.getAndIncrement(), ENABLED);
+      prepareMeasuresStatement(projectUuid);
       rs = measuresStatement.executeQuery();
+
       while (rs.next()) {
         readMeasure(rs, measures);
       }
+
+      List<String> projectBranches = selectProjectBranches(dbSession, projectUuid);
+      long biggestNcloc = selectProjectBiggestNcloc(dbSession, projectBranches);
+      String biggestBranch = selectProjectBiggestBranch(dbSession, projectBranches, biggestNcloc);
+      PreparedStatement prepareNclocByLanguageStatement = prepareNclocByLanguageStatement(dbSession, biggestBranch);
+      rs = prepareNclocByLanguageStatement.executeQuery();
+
+      if (rs.next()) {
+        readMeasure(rs, measures);
+      }
+
       return measures;
     } catch (Exception e) {
       throw new IllegalStateException(String.format("Fail to execute request to select measures of project %s", projectUuid), e);
@@ -185,6 +219,101 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea
     }
   }
 
+  private void prepareMeasuresStatement(String projectUuid) throws SQLException {
+    AtomicInteger index = new AtomicInteger(1);
+    measuresStatement.setString(index.getAndIncrement(), projectUuid);
+    METRIC_KEYS
+      .stream()
+      .filter(m -> !m.equals(NCLOC_LANGUAGE_DISTRIBUTION_KEY))
+      .forEach(DatabaseUtils.setStrings(measuresStatement, index::getAndIncrement));
+    measuresStatement.setBoolean(index.getAndIncrement(), ENABLED);
+  }
+
+  private static PreparedStatement prepareNclocByLanguageStatement(DbSession session, String projectUuid) {
+    try {
+      PreparedStatement stmt = session.getConnection().prepareStatement(SQL_NCLOC_LANGUAGE_DISTRIBUTION);
+      AtomicInteger index = new AtomicInteger(1);
+      stmt.setString(index.getAndIncrement(), projectUuid);
+      stmt.setString(index.getAndIncrement(), NCLOC_LANGUAGE_DISTRIBUTION_KEY);
+      stmt.setBoolean(index.getAndIncrement(), ENABLED);
+      return stmt;
+    } catch (SQLException e) {
+      throw new IllegalStateException("Fail to execute request to select ncloc_language_distribution measure", e);
+    }
+  }
+
+  private static List<String> selectProjectBranches(DbSession session, @Nullable String projectUuid) {
+    ResultSet rs = null;
+    List<String> projectBranches = new ArrayList<>();
+    try (PreparedStatement stmt = session.getConnection().prepareStatement(SQL_PROJECT_BRANCHES)){
+      AtomicInteger index = new AtomicInteger(1);
+      stmt.setString(index.getAndIncrement(), projectUuid);
+
+      rs = stmt.executeQuery();
+
+      while (rs.next()) {
+        String uuid = rs.getString(1);
+        projectBranches.add(uuid);
+      }
+      return projectBranches;
+    } catch (SQLException e) {
+      throw new IllegalStateException("Fail to execute request to select all project branches", e);
+    } finally {
+      DatabaseUtils.closeQuietly(rs);
+    }
+  }
+
+  private static long selectProjectBiggestNcloc(DbSession session, List<String> projectBranches) {
+    try {
+      long ncloc = 0;
+
+      AtomicInteger index = new AtomicInteger(1);
+      PreparedStatement nclocStatement = getPreparedStatement(projectBranches, SQL_BIGGEST_NCLOC_VALUE, session);
+      projectBranches.forEach(DatabaseUtils.setStrings(nclocStatement, index::getAndIncrement));
+
+      nclocStatement.setString(index.getAndIncrement(), CoreMetrics.NCLOC_KEY);
+      nclocStatement.setBoolean(index.getAndIncrement(), ENABLED);
+
+      ResultSet rs = nclocStatement.executeQuery();
+
+      if (rs.next()) {
+        ncloc = rs.getLong(1);
+      }
+      return ncloc;
+    } catch (SQLException e) {
+      throw new IllegalStateException("Fail to execute request to select the project biggest ncloc", e);
+    }
+  }
+
+  private static String selectProjectBiggestBranch(DbSession session, List<String> projectBranches, long ncloc) {
+    try {
+      String biggestBranchUuid = "";
+
+      AtomicInteger index = new AtomicInteger(1);
+      PreparedStatement nclocStatement = getPreparedStatement(projectBranches, SQL_BIGGEST_BRANCH, session);
+      projectBranches.forEach(DatabaseUtils.setStrings(nclocStatement, index::getAndIncrement));
+
+      nclocStatement.setString(index.getAndIncrement(), CoreMetrics.NCLOC_KEY);
+      nclocStatement.setLong(index.getAndIncrement(), ncloc);
+      nclocStatement.setBoolean(index.getAndIncrement(), ENABLED);
+
+      ResultSet rs = nclocStatement.executeQuery();
+
+      if (rs.next()) {
+        biggestBranchUuid = rs.getString(1);
+      }
+      return biggestBranchUuid;
+    } catch (SQLException e) {
+      throw new IllegalStateException("Fail to execute request to select the project biggest branch", e);
+    }
+  }
+
+  private static PreparedStatement getPreparedStatement(List<String> projectBranches, String replacement, DbSession session) throws SQLException {
+    String projectBranchesQuestionMarks = projectBranches.stream().map(x -> "?").collect(Collectors.joining(","));
+    String sql = StringUtils.replace(replacement, "{projectBranches}", projectBranchesQuestionMarks);
+    return session.getConnection().prepareStatement(sql);
+  }
+
   private static void readMeasure(ResultSet rs, Measures measures) throws SQLException {
     String metricKey = rs.getString(FIELD_METRIC_NAME);
     Optional<Double> value = metricKey.startsWith("new_") ? getDouble(rs, FIELD_MEASURE_VARIATION) : getDouble(rs, FIELD_MEASURE_VALUE);
index 0f013d975daee2898948f1cffb9cfd67c2c29f85..15d9976d6c23b6846235d1549447b62a471b3f54 100644 (file)
@@ -141,15 +141,22 @@ public class ProjectMeasuresIndexerIteratorTest {
   }
 
   @Test
-  public void return_language_distribution_measure() {
+  public void return_language_distribution_measure_from_biggest_branch() {
     ComponentDto project = dbTester.components().insertPrivateProject();
-    MetricDto metric = dbTester.measures().insertMetric(m -> m.setValueType(DATA.name()).setKey("ncloc_language_distribution"));
-    dbTester.measures().insertLiveMeasure(project, metric, m -> m.setValue(null).setData("<null>=2;java=6;xoo=18"));
+    MetricDto languagesDistributionMetric = dbTester.measures().insertMetric(m -> m.setValueType(DATA.name()).setKey("ncloc_language_distribution"));
+    MetricDto nclocMetric = dbTester.measures().insertMetric(m -> m.setValueType(INT.name()).setKey("ncloc"));
+
+    dbTester.measures().insertLiveMeasure(project, languagesDistributionMetric, m -> m.setValue(null).setData("<null>=2;java=6;xoo=18"));
+    dbTester.measures().insertLiveMeasure(project, nclocMetric, m -> m.setValue(26d));
+
+    ComponentDto branch = dbTester.components().insertProjectBranch(project);
+    dbTester.measures().insertLiveMeasure(branch, languagesDistributionMetric, m -> m.setValue(null).setData("<null>=4;java=12;xoo=36"));
+    dbTester.measures().insertLiveMeasure(branch, nclocMetric, m -> m.setValue(52d));
 
     Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById();
 
     assertThat(docsById.get(project.uuid()).getMeasures().getNclocByLanguages())
-      .containsOnly(entry("<null>", 2), entry("java", 6), entry("xoo", 18));
+      .containsOnly(entry("<null>", 4), entry("java", 12), entry("xoo", 36));
   }
 
   @Test
index 2c356fea4cdf16b81670f8b7fc256d50b9d1523f..83ba890ff27a176005539b3664b88c83527b3866 100644 (file)
@@ -352,11 +352,16 @@ public class SearchProjectsActionTest {
   @Test
   public void filter_projects_by_languages() {
     userSession.logIn();
-    MetricDto languagesDistribution = db.measures().insertMetric(c -> c.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setValueType("DATA"));
-    ComponentDto project1 = insertProject(new Measure(languagesDistribution, c -> c.setValue(null).setData("<null>=2;java=6;xoo=18")));
-    ComponentDto project2 = insertProject(new Measure(languagesDistribution, c -> c.setValue(null).setData("java=3;xoo=9")));
-    ComponentDto project3 = insertProject(new Measure(languagesDistribution, c -> c.setValue(null).setData("xoo=1")));
-    ComponentDto project4 = insertProject(new Measure(languagesDistribution, c -> c.setValue(null).setData("<null>=1;java=5;xoo=13")));
+    MetricDto nclocMetric = db.measures().insertMetric(c -> c.setKey(NCLOC).setValueType(INT.name()));
+    MetricDto languagesDistributionMetric = db.measures().insertMetric(c -> c.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setValueType("DATA"));
+    ComponentDto project1 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("<null>=2;java=6;xoo=18")));
+    db.measures().insertLiveMeasure(project1, nclocMetric, m -> m.setValue(26d));
+    ComponentDto project2 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("java=3;xoo=9")));
+    db.measures().insertLiveMeasure(project2, nclocMetric, m -> m.setValue(12d));
+    ComponentDto project3 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("xoo=1")));
+    db.measures().insertLiveMeasure(project3, nclocMetric, m -> m.setValue(1d));
+    ComponentDto project4 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("<null>=1;java=5;xoo=13")));
+    db.measures().insertLiveMeasure(project4, nclocMetric, m -> m.setValue(19d));
     index();
 
     SearchProjectsWsResponse result = call(request.setFilter("languages IN (java, js, <null>)"));
@@ -773,11 +778,16 @@ public class SearchProjectsActionTest {
   @Test
   public void return_languages_facet() {
     userSession.logIn();
-    MetricDto languagesDistribution = db.measures().insertMetric(c -> c.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setValueType("DATA"));
-    insertProject(new Measure(languagesDistribution, c -> c.setValue(null).setData("<null>=2;java=6;xoo=18")));
-    insertProject(new Measure(languagesDistribution, c -> c.setValue(null).setData("java=5;xoo=19")));
-    insertProject(new Measure(languagesDistribution, c -> c.setValue(null).setData("xoo=1")));
-    insertProject(new Measure(languagesDistribution, c -> c.setValue(null).setData("<null>=1;java=3;xoo=8")));
+    MetricDto nclocMetric = db.measures().insertMetric(c -> c.setKey(NCLOC).setValueType(INT.name()));
+    MetricDto languagesDistributionMetric = db.measures().insertMetric(c -> c.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setValueType("DATA"));
+    ComponentDto project1 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("<null>=2;java=6;xoo=18")));
+    db.measures().insertLiveMeasure(project1, nclocMetric, m -> m.setValue(26d));
+    ComponentDto project2 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("java=5;xoo=19")));
+    db.measures().insertLiveMeasure(project2, nclocMetric, m -> m.setValue(24d));
+    ComponentDto project3 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("xoo=1")));
+    db.measures().insertLiveMeasure(project3, nclocMetric, m -> m.setValue(1d));
+    ComponentDto project4 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("<null>=1;java=3;xoo=8")));
+    db.measures().insertLiveMeasure(project4, nclocMetric, m -> m.setValue(12d));
     index();
 
     SearchProjectsWsResponse result = call(request.setFacets(singletonList(FILTER_LANGUAGES)));
@@ -796,9 +806,12 @@ public class SearchProjectsActionTest {
   @Test
   public void return_languages_facet_with_language_having_no_project_if_language_is_in_filter() {
     userSession.logIn();
-    MetricDto languagesDistribution = db.measures().insertMetric(c -> c.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setValueType("DATA"));
-    insertProject(new Measure(languagesDistribution, c -> c.setValue(null).setData("<null>=2;java=6")));
-    insertProject(new Measure(languagesDistribution, c -> c.setValue(null).setData("java=5")));
+    MetricDto languagesDistributionMetric = db.measures().insertMetric(c -> c.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setValueType("DATA"));
+    MetricDto nclocMetric = db.measures().insertMetric(c -> c.setKey(NCLOC).setValueType(INT.name()));
+    ComponentDto project1 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("<null>=2;java=6")));
+    db.measures().insertLiveMeasure(project1, nclocMetric, m -> m.setValue(8d));
+    ComponentDto project2 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("java=5")));
+    db.measures().insertLiveMeasure(project2, nclocMetric, m -> m.setValue(5d));
     index();
 
     SearchProjectsWsResponse result = call(request.setFilter("languages = xoo").setFacets(singletonList(FILTER_LANGUAGES)));
@@ -1349,7 +1362,7 @@ public class SearchProjectsActionTest {
   private void addFavourite(@Nullable String componentUuid, @Nullable String componentKey,
     @Nullable String componentName, @Nullable String qualifier) {
     dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto().setKey("favourite")
-      .setComponentUuid(componentUuid).setUserUuid(userSession.getUuid()), userSession.getLogin(), componentKey,
+        .setComponentUuid(componentUuid).setUserUuid(userSession.getUuid()), userSession.getLogin(), componentKey,
       componentName, qualifier);
     dbSession.commit();
   }