import org.sonar.api.ExtensionPoint;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
-import org.sonar.ce.task.projectanalysis.analysis.Branch;
/**
* Extension point that is called during processing of a task
* Return the organization
*/
String getOrganizationKey();
-
- /**
- * Return the branch of the project
- */
- Branch getBranch();
}
-
}
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
-import org.sonar.ce.task.projectanalysis.analysis.Branch;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
import org.sonar.ce.task.projectanalysis.metric.Metric;
import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
public String getOrganizationKey() {
return analysisMetadataHolder.getOrganization().getKey();
}
-
- @Override
- public Branch getBranch() {
- return analysisMetadataHolder.getBranch();
- }
}
}
* If Main Branch = 100 LOCs and the "largest long-lived branch" is 120 LOCs, I'm expecting to consider the value 120.
* If Main Branch = 100 LOCs and the "largest long-lived branch" is 80 LOCs, I'm expecting to consider the value 100.
*/
- public long sumNclocOfBiggestLongLivingBranch(DbSession dbSession, String organizationUuid) {
- return sumNclocOfBiggestLongLivingBranch(dbSession, SumNclocDbQuery.builder().setOrganizationUuid(organizationUuid).build());
- }
-
public long sumNclocOfBiggestLongLivingBranch(DbSession dbSession, SumNclocDbQuery dbQuery) {
Long ncloc = mapper(dbSession).sumNclocOfBiggestLongLivingBranch(
- NCLOC_KEY, KeyType.BRANCH, BranchType.LONG, dbQuery.getOrganizationUuid(), dbQuery.getProjectUuidToExclude());
+ NCLOC_KEY, KeyType.BRANCH, BranchType.LONG, dbQuery.getOrganizationUuid(), dbQuery.getOnlyPrivateProjects(), dbQuery.getProjectUuidToExclude());
return ncloc == null ? 0L : ncloc;
}
@Param("branch") KeyType branchOrPullRequest,
@Param("branchType") BranchType branchType,
@Param("organizationUuid") String organizationUuid,
+ @Param("private") Boolean privateProject,
@Nullable @Param("projectUuidToExclude") String projectUuidToExclude);
void insert(
private final String projectUuidToExclude;
private final String organizationUuid;
+ private final Boolean onlyPrivateProjects;
public SumNclocDbQuery(Builder builder) {
projectUuidToExclude = builder.projectUuidToExclude;
organizationUuid = builder.organizationUuid;
+ onlyPrivateProjects = builder.onlyPrivateProjects;
}
@CheckForNull
return organizationUuid;
}
+ public Boolean getOnlyPrivateProjects() {
+ return onlyPrivateProjects;
+ }
+
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String projectUuidToExclude;
private String organizationUuid;
+ private Boolean onlyPrivateProjects;
private Builder() {
// to enforce use of builder()
return this;
}
+ public Builder setOnlyPrivateProjects(Boolean onlyPrivateProjects) {
+ this.onlyPrivateProjects = onlyPrivateProjects;
+ return this;
+ }
+
public SumNclocDbQuery build() {
checkNotNull(organizationUuid);
+ checkNotNull(onlyPrivateProjects);
return new SumNclocDbQuery(this);
}
}
*/
package org.sonar.db.organization;
+import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.sonar.db.DbSession;
import org.sonar.db.KeyLongValue;
import org.sonar.db.Pagination;
+import org.sonar.db.component.BranchType;
+import org.sonar.db.component.KeyType;
import org.sonar.db.qualitygate.QGateWithOrgDto;
import org.sonar.db.user.GroupDto;
import static java.util.Objects.requireNonNull;
+import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;
+import static org.sonar.db.DatabaseUtils.executeLargeUpdates;
public class OrganizationDao implements Dao {
return getMapper(dbSession).deleteByUuid(uuid);
}
+ public List<OrganizationWithNclocDto> selectOrganizationsWithNcloc(DbSession dbSession, List<String> organizationUuids) {
+ List<OrganizationWithNclocDto> result = new ArrayList<>();
+ executeLargeUpdates(organizationUuids, chunk ->
+ result.addAll(getMapper(dbSession).selectOrganizationsWithNcloc(NCLOC_KEY, chunk, KeyType.BRANCH, BranchType.LONG))
+ );
+ return result;
+ }
+
private static void checkDto(OrganizationDto organization) {
requireNonNull(organization, "OrganizationDto can't be null");
}
import org.apache.ibatis.annotations.Param;
import org.sonar.db.KeyLongValue;
import org.sonar.db.Pagination;
+import org.sonar.db.component.BranchType;
+import org.sonar.db.component.KeyType;
public interface OrganizationMapper {
void insert(@Param("organization") OrganizationDto organization, @Param("newProjectPrivate") boolean newProjectPrivate);
void updateNewProjectPrivate(@Param("organizationUuid") String organizationUuid, @Param("newProjectPrivate") boolean newProjectPrivate, @Param("now") long now);
int deleteByUuid(@Param("uuid") String uuid);
+
+ List<OrganizationWithNclocDto> selectOrganizationsWithNcloc(
+ @Param("ncloc") String ncloc,
+ @Param("organizationUuids") List<String> organizationUuids,
+ @Param("branch") KeyType branchOrPullRequest,
+ @Param("branchType") BranchType branchType);
+
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.organization;
+
+public class OrganizationWithNclocDto {
+ private String id;
+ private String kee;
+ private String name;
+ private long ncloc;
+
+ public String getId() {
+ return id;
+ }
+
+ public OrganizationWithNclocDto setId(String id) {
+ this.id = id;
+ return this;
+ }
+
+ public String getKee() {
+ return kee;
+ }
+
+ public OrganizationWithNclocDto setKee(String kee) {
+ this.kee = kee;
+ return this;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public OrganizationWithNclocDto setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public long getNcloc() {
+ return ncloc;
+ }
+
+ public OrganizationWithNclocDto setNcloc(long ncloc) {
+ this.ncloc = ncloc;
+ return this;
+ }
+}
inner join project_branches b on b.uuid = p.uuid
<where>
m.name = #{ncloc, jdbcType=VARCHAR}
+ <if test="private">
+ and p.private=${_true}
+ </if>
and p.enabled = ${_true}
and p.scope = 'PRJ'
and p.qualifier = 'TRK'
org.uuid = #{uuid, jdbcType=VARCHAR}
</select>
+ <select id="selectOrganizationsWithNcloc" resultType="org.sonar.db.organization.OrganizationWithNclocDto">
+ select o.uuid as id, o.kee as kee, o.name as name, t.ncloc as ncloc
+ from organizations o
+ left outer join (
+ select orgUuid, sum(sumncloc.maxncloc) as ncloc from (
+ select b.project_uuid, p.organization_uuid as orgUuid, max(lm.value) as maxncloc
+ from live_measures lm
+ inner join metrics m on m.id = lm.metric_id
+ inner join projects p on p.uuid = lm.component_uuid
+ inner join project_branches b on b.uuid = p.uuid
+ where
+ m.name = #{ncloc, jdbcType=VARCHAR}
+ and p.enabled = ${_true}
+ and p.private = ${_true}
+ and p.scope = 'PRJ'
+ and p.qualifier = 'TRK'
+ and p.copy_component_uuid is null
+ and p.organization_uuid in <foreach collection="organizationUuids" open="(" close=")" item="uuid" separator=",">#{uuid, jdbcType=VARCHAR}</foreach>
+ and b.branch_type = #{branchType, jdbcType=VARCHAR}
+ and b.key_type = #{branch, jdbcType=VARCHAR}
+ group by b.project_uuid, p.organization_uuid
+ ) sumncloc
+ group by orgUuid
+ ) t on t.orgUuid = o.uuid
+ where
+ o.uuid in <foreach collection="organizationUuids" open="(" close=")" item="uuid" separator=",">#{uuid, jdbcType=VARCHAR}</foreach>
+ </select>
+
<insert id="insert" parameterType="map" useGeneratedKeys="false">
insert into organizations
(
where
uuid = #{uuid, jdbcType=VARCHAR}
</delete>
-
</mapper>
db.measures().insertLiveMeasure(projectWithLinesButNoLoc, lines, m -> m.setValue(365d));
db.measures().insertLiveMeasure(projectWithLinesButNoLoc, ncloc, m -> m.setValue(0d));
- long result = underTest.sumNclocOfBiggestLongLivingBranch(db.getSession(), organization.getUuid());
+ SumNclocDbQuery query = SumNclocDbQuery.builder()
+ .setOnlyPrivateProjects(false)
+ .setOrganizationUuid(organization.getUuid())
+ .build();
+ long result = underTest.sumNclocOfBiggestLongLivingBranch(db.getSession(), query);
assertThat(result).isEqualTo(10L + 200L);
}
public void countNcloc_empty() {
db.measures().insertMetric(m -> m.setKey("ncloc").setValueType(INT.toString()));
db.measures().insertMetric(m -> m.setKey("lines").setValueType(INT.toString()));
-
- long result = underTest.sumNclocOfBiggestLongLivingBranch(db.getSession(), db.getDefaultOrganization().getUuid());
+ SumNclocDbQuery query = SumNclocDbQuery.builder()
+ .setOnlyPrivateProjects(false)
+ .setOrganizationUuid(db.getDefaultOrganization().getUuid())
+ .build();
+ long result = underTest.sumNclocOfBiggestLongLivingBranch(db.getSession(), query);
assertThat(result).isEqualTo(0L);
}
SumNclocDbQuery query = SumNclocDbQuery.builder()
.setOrganizationUuid(organization.getUuid())
.setProjectUuidToExclude(projectToExclude.uuid())
+ .setOnlyPrivateProjects(false)
.build();
long result = underTest.sumNclocOfBiggestLongLivingBranch(db.getSession(), query);
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import java.util.stream.Collectors;
+import java.util.stream.IntStream;
import javax.annotation.Nullable;
import org.apache.ibatis.exceptions.PersistenceException;
+import org.assertj.core.groups.Tuple;
import org.assertj.core.util.Lists;
import org.junit.Rule;
import org.junit.Test;
.setDefaultQualityGateUuid("1");
private static final String PERMISSION_1 = "foo";
private static final String PERMISSION_2 = "bar";
+ private static final Random RANDOM = new Random();
private System2 system2 = mock(System2.class);
tuple("+50M", 0L));
}
+ @Test
+ public void selectOrganizationsWithNcloc_on_zero_orgs() {
+ assertThat(underTest.selectOrganizationsWithNcloc(dbSession, new ArrayList<>()))
+ .isEmpty();
+ }
+
+ @Test
+ public void selectOrganizationsWithNcloc_with_not_existing_uuid() {
+ MetricDto ncloc = db.measures().insertMetric(m -> m.setKey(CoreMetrics.NCLOC_KEY));
+ OrganizationDto org1 = db.organizations().insert();
+
+ assertThat(underTest.selectOrganizationsWithNcloc(dbSession, Lists.newArrayList("xxxx")))
+ .isEmpty();
+ }
+
+ @Test
+ public void selectOrganizationsWithNcloc_with_organization_without_projects() {
+ MetricDto ncloc = db.measures().insertMetric(m -> m.setKey(CoreMetrics.NCLOC_KEY));
+ OrganizationDto org1 = db.organizations().insert();
+
+ assertThat(underTest.selectOrganizationsWithNcloc(dbSession, Lists.newArrayList(org1.getUuid())))
+ .extracting(OrganizationWithNclocDto::getId, OrganizationWithNclocDto::getKee, OrganizationWithNclocDto::getName, OrganizationWithNclocDto::getNcloc)
+ .containsExactlyInAnyOrder(
+ tuple(org1.getUuid(), org1.getKey(), org1.getName(), 0L)
+ );
+ }
+
+ @Test
+ public void selectOrganizationsWithNcloc_with_one_organization() {
+ MetricDto ncloc = db.measures().insertMetric(m -> m.setKey(CoreMetrics.NCLOC_KEY));
+ OrganizationDto org1 = db.organizations().insert();
+
+ // private project with highest ncloc in non-main branch
+ ComponentDto project1 = db.components().insertMainBranch(org1);
+ ComponentDto project1Branch = db.components().insertProjectBranch(project1);
+ db.measures().insertLiveMeasure(project1, ncloc, m -> m.setValue(1_000.0));
+ db.measures().insertLiveMeasure(project1Branch, ncloc, m -> m.setValue(110_000.0));
+
+
+ // public project that must be ignored
+ ComponentDto project2 = db.components().insertPublicProject(org1);
+ ComponentDto project2Branch = db.components().insertProjectBranch(project2);
+ db.measures().insertLiveMeasure(project2, ncloc, m -> m.setValue(1_000_000_000.0));
+ db.measures().insertLiveMeasure(project2Branch, ncloc, m -> m.setValue(1_000_000.0));
+
+ assertThat(underTest.selectOrganizationsWithNcloc(dbSession, Lists.newArrayList(org1.getUuid())))
+ .extracting(OrganizationWithNclocDto::getId, OrganizationWithNclocDto::getKee, OrganizationWithNclocDto::getName, OrganizationWithNclocDto::getNcloc)
+ .containsExactlyInAnyOrder(
+ tuple(org1.getUuid(), org1.getKey(), org1.getName(), 110_000L)
+ );
+ }
+
+ @Test
+ public void selectOrganizationsWithNcloc_with_multiple_organizations() {
+ MetricDto ncloc = db.measures().insertMetric(m -> m.setKey(CoreMetrics.NCLOC_KEY));
+
+ Tuple[] expectedResults = new Tuple[9];
+ List<String> orgUuids = new ArrayList<>();
+ IntStream.range(0, 9).forEach(
+ i -> {
+ OrganizationDto org = db.organizations().insert();
+ orgUuids.add(org.getUuid());
+
+ int maxPrivate = insertPrivateProjectsWithBranches(org, ncloc);
+ // Now we are creating public project asking for maxPrivate as minimum ncloc
+ // because those projects *MUST* not be taken during the calculation of ncloc for a private
+ // organization
+ insertPublicProjectsWithBranches(org, ncloc, maxPrivate);
+
+ expectedResults[i] = tuple(org.getUuid(), org.getKey(), org.getName(), (long) maxPrivate);
+ }
+ );
+
+ assertThat(underTest.selectOrganizationsWithNcloc(dbSession, orgUuids))
+ .extracting(OrganizationWithNclocDto::getId, OrganizationWithNclocDto::getKee, OrganizationWithNclocDto::getName, OrganizationWithNclocDto::getNcloc)
+ .containsExactlyInAnyOrder(expectedResults);
+ }
+
private void expectDtoCanNotBeNull() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("OrganizationDto can't be null");
preparedStatement.setString(5, view);
preparedStatement.setBoolean(6, false);
preparedStatement.setBoolean(7, false);
- preparedStatement.setString(8, "1"); // TODO check ok ?
- preparedStatement.setString(9, FREE.name()); // TODO check ok ?
+ preparedStatement.setString(8, "1");
+ preparedStatement.setString(9, FREE.name());
preparedStatement.setLong(10, 1000L);
preparedStatement.setLong(11, 2000L);
preparedStatement.execute();
Map<String, Object> row = db.selectFirst(db.getSession(), String.format("select updated_at as \"updatedAt\" from organizations where uuid='%s'", organization));
assertThat(row.get("updatedAt")).isEqualTo(updatedAt);
}
+
+ private int insertPrivateProjectsWithBranches(OrganizationDto org, MetricDto ncloc) {
+ // private project
+ ComponentDto project1 = db.components().insertMainBranch(org);
+
+ return Math.max(
+ // Create the ncloc on main branch
+ insertLiveMeasures(project1, ncloc, 0),
+ // Create 5 branches and set the ncloc on them
+ IntStream.range(1, 5)
+ .map(i -> insertLiveMeasures(db.components().insertProjectBranch(project1), ncloc, 0))
+ .max().orElse(0)
+ );
+ }
+
+ private int insertPublicProjectsWithBranches(OrganizationDto org, MetricDto ncloc, int minimumNcloc) {
+ // private project
+ ComponentDto project1 = db.components().insertPublicProject(org);
+
+ return Math.max(
+ // Create the ncloc on main branch
+ insertLiveMeasures(project1, ncloc, minimumNcloc),
+ // Create 5 branches and set the ncloc on them
+ IntStream.range(1, 5)
+ .map(i -> insertLiveMeasures(db.components().insertProjectBranch(project1), ncloc, minimumNcloc))
+ .max().orElse(0)
+ );
+ }
+
+ private int insertLiveMeasures(ComponentDto componentDto, MetricDto ncloc, int minimum) {
+ int nclocValue = minimum + RANDOM.nextInt(1_000_000);
+ db.measures().insertLiveMeasure(componentDto, ncloc, m -> m.setValue((double) nclocValue));
+ return nclocValue;
+ }
}
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
+import org.sonar.db.measure.SumNclocDbQuery;
import org.sonar.server.es.SearchOptions;
import org.sonar.server.measure.index.ProjectMeasuresIndex;
import org.sonar.server.measure.index.ProjectMeasuresStatistics;
try (DbSession dbSession = dbClient.openSession(false)) {
data.setDatabase(loadDatabaseMetadata(dbSession));
data.setUsingBranches(dbClient.branchDao().hasNonMainBranches(dbSession));
- data.setNcloc(dbClient.liveMeasureDao().sumNclocOfBiggestLongLivingBranch(dbSession, defaultOrganizationProvider.get().getUuid()));
+ SumNclocDbQuery query = SumNclocDbQuery.builder()
+ .setOnlyPrivateProjects(false)
+ .setOrganizationUuid(defaultOrganizationProvider.get().getUuid())
+ .build();
+ data.setNcloc(dbClient.liveMeasureDao().sumNclocOfBiggestLongLivingBranch(dbSession, query));
}
return data.build();
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.organization.DefaultOrganizationProvider;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.Navigation;
private long computeNcloc() {
try (DbSession dbSession = dbClient.openSession(false)) {
- return dbClient.liveMeasureDao().sumNclocOfBiggestLongLivingBranch(dbSession, defaultOrganizationProvider.get().getUuid());
+ SumNclocDbQuery query = SumNclocDbQuery.builder()
+ .setOnlyPrivateProjects(false)
+ .setOrganizationUuid(defaultOrganizationProvider.get().getUuid())
+ .build();
+ return dbClient.liveMeasureDao().sumNclocOfBiggestLongLivingBranch(dbSession, query);
}
}
}