"project_mappings",
"project_measures",
"project_qprofiles",
+ "project_qgates",
"properties",
"push_events",
"qprofile_changes",
return mapper(dbSession).selectProjects(query);
}
+ public List<ProjectQgateAssociationDto> selectAll(DbSession dbSession) {
+ return mapper(dbSession).selectAll();
+ }
+
/**
* @return quality gate uuid if a specific Quality Gate has been defined for the given project uuid. <br>
* Returns <code>{@link Optional#empty()}</code> otherwise (ex: default quality gate applies)
List<ProjectQgateAssociationDto> selectProjects(@Param("query") ProjectQgateAssociationQuery query);
+ List<ProjectQgateAssociationDto> selectAll();
+
@CheckForNull
String selectQGateUuidByProjectUuid(String projectUuid);
order by proj.name, proj.kee
</select>
+ <select id="selectAll" resultType="ProjectQgateAssociation">
+ SELECT project_uuid as uuid, quality_gate_uuid as gateUuid
+ FROM project_qgates
+ </select>
+
<select id="selectQGateUuidByProjectUuid" parameterType="String" resultType="string">
SELECT quality_gate_uuid
FROM project_qgates
.containsExactly(project1.uuid(), project3.uuid(), project2.uuid());
}
+ @Test
+ public void select_all() {
+ List<ProjectQgateAssociationDto> t = underTest.selectAll(dbSession);
+
+ QualityGateDto qualityGate1 = db.qualityGates().insertQualityGate();
+ QualityGateDto qualityGate2 = db.qualityGates().insertQualityGate();
+ ComponentDto project1 = db.components().insertPrivateProject();
+ ComponentDto project2 = db.components().insertPrivateProject();
+ ComponentDto project3 = db.components().insertPrivateProject();
+ ComponentDto project4 = db.components().insertPrivateProject();
+ ComponentDto project5 = db.components().insertPrivateProject();
+ db.qualityGates().associateProjectToQualityGate(db.components().getProjectDto(project1), qualityGate1);
+ db.qualityGates().associateProjectToQualityGate(db.components().getProjectDto(project2), qualityGate2);
+ db.qualityGates().associateProjectToQualityGate(db.components().getProjectDto(project3), qualityGate1);
+ db.qualityGates().associateProjectToQualityGate(db.components().getProjectDto(project4), qualityGate2);
+ db.qualityGates().associateProjectToQualityGate(db.components().getProjectDto(project5), qualityGate1);
+
+ List<ProjectQgateAssociationDto> result = underTest.selectAll(dbSession);
+
+ assertThat(result)
+ .extracting(ProjectQgateAssociationDto::getUuid, ProjectQgateAssociationDto::getGateUuid)
+ .containsExactlyInAnyOrder(
+ tuple(project1.uuid(), qualityGate1.getUuid()),
+ tuple(project2.uuid(), qualityGate2.getUuid()),
+ tuple(project3.uuid(), qualityGate1.getUuid()),
+ tuple(project4.uuid(), qualityGate2.getUuid()),
+ tuple(project5.uuid(), qualityGate1.getUuid()));
+ }
+
@Test
public void select_qgate_uuid_is_absent() {
ComponentDto project = db.components().insertPrivateProject();
private final Map<String, String> plugins;
private final Database database;
private final EditionProvider.Edition edition;
+ private final String defaultQualityGate;
private final Long installationDate;
private final String installationVersion;
private final boolean inDocker;
private final List<UserTelemetryDto> users;
private final List<Project> projects;
private final List<ProjectStatistics> projectStatistics;
+ private final List<QualityGate> qualityGates;
private final Boolean hasUnanalyzedC;
private final Boolean hasUnanalyzedCpp;
private final Set<String> customSecurityConfigs;
plugins = builder.plugins;
database = builder.database;
edition = builder.edition;
+ defaultQualityGate = builder.defaultQualityGate;
installationDate = builder.installationDate;
installationVersion = builder.installationVersion;
inDocker = builder.inDocker;
users = builder.users;
projects = builder.projects;
projectStatistics = builder.projectStatistics;
+ qualityGates = builder.qualityGates;
hasUnanalyzedC = builder.hasUnanalyzedC;
hasUnanalyzedCpp = builder.hasUnanalyzedCpp;
customSecurityConfigs = requireNonNullElse(builder.customSecurityConfigs, Set.of());
return Optional.ofNullable(edition);
}
+ public String getDefaultQualityGate() {
+ return defaultQualityGate;
+ }
+
public Long getInstallationDate() {
return installationDate;
}
return projectStatistics;
}
+ public List<QualityGate> getQualityGates() {
+ return qualityGates;
+ }
+
static Builder builder() {
return new Builder();
}
private Map<String, String> plugins;
private Database database;
private Edition edition;
+ private String defaultQualityGate;
private Long installationDate;
private String installationVersion;
private boolean inDocker = false;
private List<UserTelemetryDto> users;
private List<Project> projects;
private List<ProjectStatistics> projectStatistics;
+ private List<QualityGate> qualityGates;
private Builder() {
// enforce static factory method
return this;
}
+ Builder setDefaultQualityGate(String defaultQualityGate) {
+ this.defaultQualityGate = defaultQualityGate;
+ return this;
+ }
+
Builder setInstallationDate(@Nullable Long installationDate) {
this.installationDate = installationDate;
return this;
return this;
}
+ Builder setQualityGates(List<QualityGate> qualityGates) {
+ this.qualityGates = qualityGates;
+ return this;
+ }
+
private static void requireNonNullValues(Object... values) {
Arrays.stream(values).forEach(Objects::requireNonNull);
}
record Project(String projectUuid, Long lastAnalysis, String language, Long loc) {
}
- record ProjectStatistics(String projectUuid, Long branchCount, Long pullRequestCount, String scm, String ci, String devopsPlatform) {
- ProjectStatistics(String projectUuid, Long branchCount, Long pullRequestCount,
- @Nullable String scm, @Nullable String ci, @Nullable String devopsPlatform) {
- this.projectUuid = projectUuid;
- this.branchCount = branchCount;
- this.pullRequestCount = pullRequestCount;
- this.scm = scm;
- this.ci = ci;
- this.devopsPlatform = devopsPlatform;
- }
+ record ProjectStatistics(String projectUuid, Long branchCount, Long pullRequestCount, String qualityGate, String scm, String ci, String devopsPlatform) {
+ }
+
+ record QualityGate(String uuid, boolean isCaycCompliant) {
}
}
json.prop("messageSequenceNumber", statistics.getMessageSequenceNumber());
json.prop("localTimestamp", toUtc(system2.now()));
statistics.getEdition().ifPresent(e -> json.prop("edition", e.name().toLowerCase(Locale.ENGLISH)));
+ json.prop("defaultQualityGate", statistics.getDefaultQualityGate());
json.name("database");
json.beginObject();
json.prop("name", statistics.getDatabase().name());
writeUserData(json, statistics);
writeProjectData(json, statistics);
writeProjectStatsData(json, statistics);
+ writeQualityGates(json, statistics);
extensions.forEach(e -> e.write(json));
json.prop("projectUuid", project.projectUuid());
json.prop("branchCount", project.branchCount());
json.prop("pullRequestCount", project.pullRequestCount());
+ json.prop("qualityGate", project.qualityGate());
json.prop("scm", project.scm());
json.prop("ci", project.ci());
json.prop("devopsPlatform", project.devopsPlatform());
}
}
+ private static void writeQualityGates(JsonWriter json, TelemetryData statistics) {
+ if (statistics.getQualityGates() != null) {
+ json.name("quality-gates");
+ json.beginArray();
+ statistics.getQualityGates().forEach(qualityGate -> {
+ json.beginObject();
+ json.prop("uuid", qualityGate.uuid());
+ json.prop("isCaycCompliant", qualityGate.isCaycCompliant());
+ json.endObject();
+ });
+ json.endArray();
+ }
+ }
+
@NotNull
private static String toUtc(long date) {
return DateTimeFormatter.ofPattern(DATETIME_FORMAT)
TelemetryData data = telemetryBuilder().build();
String json = writeTelemetryData(data);
-
- assertJson(json).isSimilarTo("{" +
- " \"id\": \"" + data.getServerId() + "\"," +
- " \"version\": \"" + data.getVersion() + "\"," +
- " \"messageSequenceNumber\": " + data.getMessageSequenceNumber() +
- "}");
+ assertJson(json).isSimilarTo("""
+ {
+ "id": "%s",
+ "version": "%s",
+ "messageSequenceNumber": %s
+ }
+ """.formatted(data.getServerId(), data.getVersion(), data.getMessageSequenceNumber()));
}
@Test
.build();
String json = writeTelemetryData(data);
+ assertJson(json).isSimilarTo("""
+ {
+ "edition": "%s"
+ }
+ """.formatted(edition.name().toLowerCase(Locale.ENGLISH)));
+ }
+
+ @Test
+ public void writes_default_qg() {
+ TelemetryData data = telemetryBuilder()
+ .setDefaultQualityGate("default-qg")
+ .build();
- assertJson(json).isSimilarTo("{" +
- " \"edition\": \"" + edition.name().toLowerCase(Locale.ENGLISH) + "\"" +
- "}");
+ String json = writeTelemetryData(data);
+ assertJson(json).isSimilarTo("""
+ {
+ "defaultQualityGate": "%s"
+ }
+ """.formatted(data.getDefaultQualityGate()));
}
@Test
.build();
String json = writeTelemetryData(data);
-
- assertJson(json).isSimilarTo("{" +
- " \"database\": {" +
- " \"name\": \"" + name + "\"," +
- " \"version\": \"" + version + "\"" +
- " }" +
- "}");
+ assertJson(json).isSimilarTo("""
+ {
+ "database": {
+ "name": "%s",
+ "version": "%s"
+ }
+ }
+ """.formatted(name, version));
}
@Test
String json = writeTelemetryData(data);
- assertJson(json).isSimilarTo("{" +
- " \"plugins\": []" +
- "}");
+ assertJson(json).isSimilarTo("""
+ {
+ "plugins": []
+ }
+ """);
}
@Test
.build();
String json = writeTelemetryData(data);
-
- assertJson(json).isSimilarTo("{" +
- " \"plugins\": " +
- "[" +
- plugins.entrySet().stream().map(e -> "{\"name\":\"" + e.getKey() + "\",\"version\":\"" + e.getValue() + "\"}").collect(joining(",")) +
- "]" +
- "}");
+ assertJson(json).isSimilarTo("""
+ {
+ "plugins": [%s]
+ }
+ """.formatted(plugins.entrySet().stream().map(e -> "{\"name\":\"" + e.getKey() + "\",\"version\":\"" + e.getValue() + "\"}").collect(joining(","))));
}
@Test
String json = writeTelemetryData(data);
- assertJson(json).isSimilarTo("{" +
- " \"installationDate\":\"1970-01-01T00:00:01+0000\"," +
- "}");
+ assertJson(json).isSimilarTo("""
+ {
+ "installationDate":"1970-01-01T00:00:01+0000"
+ }
+ """);
}
@Test
.build();
String json = writeTelemetryData(data);
-
- assertJson(json).isSimilarTo("{" +
- " \"installationVersion\":\"" + installationVersion + "\"" +
- "}");
+ assertJson(json).isSimilarTo("""
+ {
+ "installationVersion": "%s"
+ }
+ """.formatted(installationVersion));
}
@Test
.build();
String json = writeTelemetryData(data);
-
- assertJson(json).isSimilarTo("{" +
- " \"docker\":" + isInDocker +
- "}");
+ assertJson(json).isSimilarTo("""
+ {
+ "docker": %s
+ }
+ """.formatted(isInDocker));
}
@Test
String json = writeTelemetryData(data);
- assertJson(json).isSimilarTo("{" +
- " \"customSecurityConfig\": [\"php\", \"java\"]" +
- "}");
+ assertJson(json).isSimilarTo("""
+ {
+ "customSecurityConfig": ["php", "java"]
+ }
+ """);
}
@Test
TelemetryData data = telemetryBuilder().build();
String json = writeTelemetryData(data);
- assertJson(json).isSimilarTo("{" +
- " \"localTimestamp\": \"1970-01-01T00:00:01+0000\"" +
- "}");
+ assertJson(json).isSimilarTo("""
+ {
+ "localTimestamp": "1970-01-01T00:00:01+0000"
+ }
+ """);
}
@Test
String json = writeTelemetryData(data);
- assertJson(json).isSimilarTo("{" +
- " \"users\": [" +
- " {" +
- " \"userUuid\":\"" + DigestUtils.sha3_224Hex("uuid-0") + "\"," +
- " \"lastActivity\":\"1970-01-01T00:00:00+0000\"," +
- " \"identityProvider\":\"gitlab\"," +
- " \"lastSonarlintActivity\":\"1970-01-01T00:00:00+0000\"," +
- " \"status\":\"active\"" +
- " }," +
- " {" +
- " \"userUuid\":\"" + DigestUtils.sha3_224Hex("uuid-1") + "\"," +
- " \"lastActivity\":\"1970-01-01T00:00:00+0000\"," +
- " \"identityProvider\":\"gitlab\"," +
- " \"lastSonarlintActivity\":\"1970-01-01T00:00:00+0000\"," +
- " \"status\":\"inactive\"" +
- " }," +
- " {" +
- " \"userUuid\":\"" + DigestUtils.sha3_224Hex("uuid-2") + "\"," +
- " \"lastActivity\":\"1970-01-01T00:00:00+0000\"," +
- " \"identityProvider\":\"gitlab\"," +
- " \"lastSonarlintActivity\":\"1970-01-01T00:00:00+0000\"," +
- " \"status\":\"active\"" +
- " }" +
- " ]" +
- "}");
+ assertJson(json).isSimilarTo("""
+ {
+ "users": [
+ {
+ "userUuid": "%s",
+ "status": "active",
+ "identityProvider": "gitlab",
+ "lastActivity": "1970-01-01T00:00:00+0000",
+ "lastSonarlintActivity": "1970-01-01T00:00:00+0000"
+ },
+ {
+ "userUuid": "%s",
+ "status": "inactive",
+ "identityProvider": "gitlab",
+ "lastActivity": "1970-01-01T00:00:00+0000",
+ "lastSonarlintActivity": "1970-01-01T00:00:00+0000"
+ },
+ {
+ "userUuid": "%s",
+ "status": "active",
+ "identityProvider": "gitlab",
+ "lastActivity": "1970-01-01T00:00:00+0000",
+ "lastSonarlintActivity": "1970-01-01T00:00:00+0000"
+ }
+ ]
+ }
+ """
+ .formatted(DigestUtils.sha3_224Hex("uuid-0"), DigestUtils.sha3_224Hex("uuid-1"), DigestUtils.sha3_224Hex("uuid-2")));
}
@Test
String json = writeTelemetryData(data);
- assertJson(json).isSimilarTo("{" +
- " \"projects\": [" +
- " {" +
- " \"projectUuid\": \"uuid-0\"," +
- " \"lastAnalysis\":\"1970-01-01T00:00:00+0000\"," +
- " \"language\": \"lang-0\"," +
- " \"loc\": 2" +
- " }," +
- " {" +
- " \"projectUuid\": \"uuid-1\"," +
- " \"lastAnalysis\":\"1970-01-01T00:00:00+0000\"," +
- " \"language\": \"lang-1\"," +
- " \"loc\": 4" +
- " }," +
- " {" +
- " \"projectUuid\": \"uuid-2\"," +
- " \"lastAnalysis\":\"1970-01-01T00:00:00+0000\"," +
- " \"language\": \"lang-2\"," +
- " \"loc\": 6" +
- " }" +
- " ]" +
- "}");
+ assertJson(json).isSimilarTo("""
+ {
+ "projects": [
+ {
+ "projectUuid": "uuid-0",
+ "lastAnalysis": "1970-01-01T00:00:00+0000",
+ "language": "lang-0",
+ "loc": 2
+ },
+ {
+ "projectUuid": "uuid-1",
+ "lastAnalysis": "1970-01-01T00:00:00+0000",
+ "language": "lang-1",
+ "loc": 4
+ },
+ {
+ "projectUuid": "uuid-2",
+ "lastAnalysis": "1970-01-01T00:00:00+0000",
+ "language": "lang-2",
+ "loc": 6
+ }
+ ]
+ }
+ """);
}
@Test
"projectUuid": "uuid-0",
"branchCount": 2,
"pullRequestCount": 2,
+ "qualityGate": "qg-0"
"scm": "scm-0",
"ci": "ci-0",
"devopsPlatform": "devops-0"
"projectUuid": "uuid-1",
"branchCount": 4,
"pullRequestCount": 4,
+ "qualityGate": "qg-1"
"scm": "scm-1",
"ci": "ci-1",
"devopsPlatform": "devops-1"
"projectUuid": "uuid-2",
"branchCount": 6,
"pullRequestCount": 6,
+ "qualityGate": "qg-2"
"scm": "scm-2",
"ci": "ci-2",
"devopsPlatform": "devops-2"
assertThat(json).doesNotContain("hasUnanalyzedC", "hasUnanalyzedCpp");
}
+ @Test
+ public void writes_all_quality_gates() {
+ TelemetryData data = telemetryBuilder()
+ .setQualityGates(attachQualityGates())
+ .build();
+
+ String json = writeTelemetryData(data);
+ assertJson(json).isSimilarTo("""
+ {
+ "quality-gates": [
+ {
+ "uuid": "uuid-0",
+ "isCaycCompliant": true
+ },
+ {
+ "uuid": "uuid-1",
+ "isCaycCompliant": false
+ },
+ {
+ "uuid": "uuid-2",
+ "isCaycCompliant": true
+ }
+ ]
+ }
+ """
+ );
+ }
+
private static TelemetryData.Builder telemetryBuilder() {
return TelemetryData.builder()
.setServerId("foo")
}
private List<TelemetryData.ProjectStatistics> attachProjectStats() {
- return IntStream.range(0, 3).mapToObj(i -> new TelemetryData.ProjectStatistics("uuid-" + i, (i + 1L) * 2L, (i + 1L) * 2L, "scm-" + i, "ci-" + i, "devops-" + i))
+ return IntStream.range(0, 3).mapToObj(i -> new TelemetryData.ProjectStatistics("uuid-" + i, (i + 1L) * 2L, (i + 1L) * 2L, "qg-" + i, "scm-" + i, "ci-" + i, "devops-" + i))
+ .collect(Collectors.toList());
+ }
+
+ private List<TelemetryData.QualityGate> attachQualityGates() {
+ return IntStream.range(0, 3).mapToObj(i -> new TelemetryData.QualityGate("uuid-" + i, i % 2 == 0))
.collect(Collectors.toList());
}
api project(':sonar-markdown')
api project(':sonar-plugin-api-impl')
api project(':sonar-ws')
+ implementation project(path: ':server:sonar-webserver-webapi')
compileOnlyApi 'com.google.code.findbugs:jsr305'
// not a transitive dep. At runtime lib/jdbc/h2 is used
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.sonar.db.component.AnalysisPropertyValuePerProject;
import org.sonar.db.component.PrBranchAnalyzedLanguageCountByProjectDto;
import org.sonar.db.measure.ProjectMeasureDto;
+import org.sonar.db.qualitygate.ProjectQgateAssociationDto;
+import org.sonar.db.qualitygate.QualityGateDto;
import org.sonar.server.platform.DockerSupport;
import org.sonar.server.property.InternalProperties;
+import org.sonar.server.qualitygate.QualityGateCaycChecker;
+import org.sonar.server.qualitygate.QualityGateFinder;
import org.sonar.server.telemetry.TelemetryData.Database;
import static java.util.Arrays.asList;
private final Configuration configuration;
private final InternalProperties internalProperties;
private final DockerSupport dockerSupport;
+ private final QualityGateCaycChecker qualityGateCaycChecker;
+ private final QualityGateFinder qualityGateFinder;
@Inject
public TelemetryDataLoaderImpl(Server server, DbClient dbClient, PluginRepository pluginRepository,
PlatformEditionProvider editionProvider, InternalProperties internalProperties, Configuration configuration,
- DockerSupport dockerSupport) {
+ DockerSupport dockerSupport, QualityGateCaycChecker qualityGateCaycChecker, QualityGateFinder qualityGateFinder) {
this.server = server;
this.dbClient = dbClient;
this.pluginRepository = pluginRepository;
this.internalProperties = internalProperties;
this.configuration = configuration;
this.dockerSupport = dockerSupport;
+ this.qualityGateCaycChecker = qualityGateCaycChecker;
+ this.qualityGateFinder = qualityGateFinder;
}
private static Database loadDatabaseMetadata(DbSession dbSession) {
try (DbSession dbSession = dbClient.openSession(false)) {
data.setDatabase(loadDatabaseMetadata(dbSession));
+ String defaultQualityGateUuid = qualityGateFinder.getDefault(dbSession).getUuid();
+
+ data.setDefaultQualityGate(defaultQualityGateUuid);
resolveUnanalyzedLanguageCode(data, dbSession);
- resolveProjectStatistics(data, dbSession);
+ resolveProjectStatistics(data, dbSession, defaultQualityGateUuid);
resolveProjects(data, dbSession);
+ resolveQualityGates(data, dbSession);
resolveUsers(data, dbSession);
}
return internalProperties.read(I_PROP_MESSAGE_SEQUENCE).map(Long::parseLong).orElse(0L);
}
- private void resolveProjectStatistics(TelemetryData.Builder data, DbSession dbSession) {
+ private void resolveProjectStatistics(TelemetryData.Builder data, DbSession dbSession, String defaultQualityGateUuid) {
List<String> projectUuids = dbClient.projectDao().selectAllProjectUuids(dbSession);
Map<String, String> scmByProject = getAnalysisPropertyByProject(dbSession, SONAR_ANALYSIS_DETECTEDSCM);
Map<String, String> ciByProject = getAnalysisPropertyByProject(dbSession, SONAR_ANALYSIS_DETECTEDCI);
Map<String, PrBranchAnalyzedLanguageCountByProjectDto> prAndBranchCountByProjects = dbClient.branchDao().countPrBranchAnalyzedLanguageByProjectUuid(dbSession)
.stream().collect(Collectors.toMap(PrBranchAnalyzedLanguageCountByProjectDto::getProjectUuid, Function.identity()));
+
+ Map<String, String> projectQgatesMap = getProjectQgatesMap(dbSession);
+
List<TelemetryData.ProjectStatistics> projectStatistics = new ArrayList<>();
for (String projectUuid : projectUuids) {
Optional<PrBranchAnalyzedLanguageCountByProjectDto> counts = ofNullable(prAndBranchCountByProjects.get(projectUuid));
Long branchCount = counts.map(PrBranchAnalyzedLanguageCountByProjectDto::getBranch).orElse(0L);
Long pullRequestCount = counts.map(PrBranchAnalyzedLanguageCountByProjectDto::getPullRequest).orElse(0L);
+ String qualityGate = projectQgatesMap.getOrDefault(projectUuid, defaultQualityGateUuid);
String scm = Optional.ofNullable(scmByProject.get(projectUuid)).orElse(UNDETECTED);
String ci = Optional.ofNullable(ciByProject.get(projectUuid)).orElse(UNDETECTED);
String devopsPlatform = null;
devopsPlatform = Optional.ofNullable(devopsPlatform).orElse(UNDETECTED);
projectStatistics.add(
- new TelemetryData.ProjectStatistics(projectUuid, branchCount, pullRequestCount, scm, ci, devopsPlatform));
+ new TelemetryData.ProjectStatistics(projectUuid, branchCount, pullRequestCount, qualityGate, scm, ci, devopsPlatform));
}
data.setProjectStatistics(projectStatistics);
}
data.setProjects(projects);
}
+ private void resolveQualityGates(TelemetryData.Builder data, DbSession dbSession) {
+ List<TelemetryData.QualityGate> qualityGates = new ArrayList<>();
+ Collection<QualityGateDto> qualityGateDtos = dbClient.qualityGateDao().selectAll(dbSession);
+ for (QualityGateDto qualityGateDto : qualityGateDtos) {
+ qualityGates.add(
+ new TelemetryData.QualityGate(qualityGateDto.getUuid(), qualityGateCaycChecker.checkCaycCompliant(dbSession, qualityGateDto.getUuid()))
+ );
+ }
+
+ data.setQualityGates(qualityGates);
+ }
+
private void resolveUsers(TelemetryData.Builder data, DbSession dbSession) {
data.setUsers(dbClient.userDao().selectUsersForTelemetry(dbSession));
}
return alm + "_server";
}
+ private Map<String, String> getProjectQgatesMap(DbSession dbSession) {
+ return dbClient.projectQgateAssociationDao().selectAll(dbSession)
+ .stream()
+ .collect(Collectors.toMap(ProjectQgateAssociationDto::getUuid, p -> Optional.ofNullable(p.getGateUuid()).orElse("")));
+ }
+
private static boolean checkIfCloudAlm(String almRaw, String alm, String url, String cloudUrl) {
return alm.equals(almRaw) && startsWithIgnoreCase(url, cloudUrl);
}
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.SnapshotDto;
import org.sonar.db.metric.MetricDto;
+import org.sonar.db.qualitygate.QualityGateDto;
import org.sonar.db.user.UserDbTester;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserTelemetryDto;
import org.sonar.server.platform.DockerSupport;
import org.sonar.server.property.InternalProperties;
import org.sonar.server.property.MapInternalProperties;
+import org.sonar.server.qualitygate.QualityGateCaycChecker;
+import org.sonar.server.qualitygate.QualityGateFinder;
import org.sonar.updatecenter.common.Version;
import static java.util.Arrays.asList;
private final Configuration configuration = mock(Configuration.class);
private final PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
private final DockerSupport dockerSupport = mock(DockerSupport.class);
+ private final QualityGateCaycChecker qualityGateCaycChecker = mock(QualityGateCaycChecker.class);
+ private final QualityGateFinder qualityGateFinder = new QualityGateFinder(db.getDbClient());
private final InternalProperties internalProperties = spy(new MapInternalProperties());
private final TelemetryDataLoader communityUnderTest = new TelemetryDataLoaderImpl(server, db.getDbClient(), pluginRepository, editionProvider,
- internalProperties, configuration, dockerSupport);
+ internalProperties, configuration, dockerSupport, qualityGateCaycChecker, qualityGateFinder);
private final TelemetryDataLoader commercialUnderTest = new TelemetryDataLoaderImpl(server, db.getDbClient(), pluginRepository, editionProvider,
- internalProperties, configuration, dockerSupport);
+ internalProperties, configuration, dockerSupport, qualityGateCaycChecker, qualityGateFinder);
+
+ private QualityGateDto builtInDefaultQualityGate;
+
+ @Before
+ public void setUpBuiltInQualityGate() {
+ String builtInQgName = "Sonar Way";
+ builtInDefaultQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName(builtInQgName).setBuiltIn(true));
+ db.qualityGates().setDefaultQualityGate(builtInDefaultQualityGate);
+ }
@Test
public void send_telemetry_data() {
db.almSettings().insertAzureProjectAlmSetting(almSettingDto, db.components().getProjectDto(project1));
db.almSettings().insertGitlabProjectAlmSetting(gitHubAlmSetting, db.components().getProjectDto(project2));
+ // quality gates
+ QualityGateDto qualityGate1 = db.qualityGates().insertQualityGate(qg -> qg.setName("QG1").setBuiltIn(true));
+ QualityGateDto qualityGate2 = db.qualityGates().insertQualityGate(qg -> qg.setName("QG2"));
+
+ // link one project to a non-default QG
+ db.qualityGates().associateProjectToQualityGate(db.components().getProjectDto(project1), qualityGate1);
+
TelemetryData data = communityUnderTest.load();
assertThat(data.getServerId()).isEqualTo(serverId);
assertThat(data.getVersion()).isEqualTo(version);
assertThat(data.getEdition()).contains(DEVELOPER);
+ assertThat(data.getDefaultQualityGate()).isEqualTo(builtInDefaultQualityGate.getUuid());
assertThat(data.getMessageSequenceNumber()).isOne();
assertDatabaseMetadata(data.getDatabase());
assertThat(data.getPlugins()).containsOnly(
tuple(project2.uuid(), "java", 180L, analysisDate),
tuple(project2.uuid(), "js", 20L, analysisDate));
assertThat(data.getProjectStatistics())
- .extracting(TelemetryData.ProjectStatistics::branchCount, TelemetryData.ProjectStatistics::pullRequestCount,
+ .extracting(TelemetryData.ProjectStatistics::branchCount, TelemetryData.ProjectStatistics::pullRequestCount, TelemetryData.ProjectStatistics::qualityGate,
TelemetryData.ProjectStatistics::scm, TelemetryData.ProjectStatistics::ci, TelemetryData.ProjectStatistics::devopsPlatform)
.containsExactlyInAnyOrder(
- tuple(1L, 0L, "scm-1", "ci-1", "azure_devops_cloud"),
- tuple(1L, 0L, "scm-2", "ci-2", "github_cloud"));
+ tuple(1L, 0L, qualityGate1.getUuid(), "scm-1", "ci-1", "azure_devops_cloud"),
+ tuple(1L, 0L, builtInDefaultQualityGate.getUuid(), "scm-2", "ci-2", "github_cloud"));
+ assertThat(data.getQualityGates())
+ .extracting(TelemetryData.QualityGate::uuid, TelemetryData.QualityGate::isCaycCompliant)
+ .containsExactlyInAnyOrder(
+ tuple(builtInDefaultQualityGate.getUuid(), false),
+ tuple(qualityGate1.getUuid(), false),
+ tuple(qualityGate2.getUuid(), false)
+ );
}
private List<UserDto> composeActiveUsers(int count) {
assertThat(data.isScimEnabled()).isEqualTo(isEnabled);
}
+ @Test
+ public void default_quality_gate_sent_with_project() {
+ db.components().insertPublicProject();
+ QualityGateDto qualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("anything").setBuiltIn(true));
+ db.qualityGates().setDefaultQualityGate(qualityGate);
+ TelemetryData data = communityUnderTest.load();
+ assertThat(data.getProjectStatistics())
+ .extracting(TelemetryData.ProjectStatistics::qualityGate)
+ .containsOnly(qualityGate.getUuid());
+ }
+
private PluginInfo newPlugin(String key, String version) {
return new PluginInfo(key)
.setVersion(Version.create(version));