private final Long installationDate;
private final String installationVersion;
private final boolean inDocker;
- private final boolean isScimEnabled;
+ private final ManagedInstanceInformation managedInstanceInformation;
private final List<UserTelemetryDto> users;
private final List<Project> projects;
private final List<ProjectStatistics> projectStatistics;
installationDate = builder.installationDate;
installationVersion = builder.installationVersion;
inDocker = builder.inDocker;
- isScimEnabled = builder.isScimEnabled;
users = builder.users;
projects = builder.projects;
projectStatistics = builder.projectStatistics;
hasUnanalyzedC = builder.hasUnanalyzedC;
hasUnanalyzedCpp = builder.hasUnanalyzedCpp;
customSecurityConfigs = requireNonNullElse(builder.customSecurityConfigs, Set.of());
+ managedInstanceInformation = builder.managedInstanceInformation;
}
public String getServerId() {
return inDocker;
}
- public boolean isScimEnabled() {
- return isScimEnabled;
+ public ManagedInstanceInformation getManagedInstanceInformation() {
+ return managedInstanceInformation;
}
public Optional<Boolean> hasUnanalyzedC() {
private Long installationDate;
private String installationVersion;
private boolean inDocker = false;
- private boolean isScimEnabled;
+ private ManagedInstanceInformation managedInstanceInformation;
private Boolean hasUnanalyzedC;
private Boolean hasUnanalyzedCpp;
private Set<String> customSecurityConfigs;
return this;
}
- public Builder setIsScimEnabled(boolean isEnabled) {
- this.isScimEnabled = isEnabled;
+ Builder setManagedInstanceInformation(ManagedInstanceInformation managedInstanceInformation) {
+ this.managedInstanceInformation = managedInstanceInformation;
return this;
}
record QualityGate(String uuid, String caycStatus) {
}
+ record ManagedInstanceInformation(boolean isManaged, @Nullable String provider) {
+ }
+
public static class ProjectStatistics {
private final String projectUuid;
private final Long branchCount;
public class TelemetryDataJsonWriter {
@VisibleForTesting
- static final String SCIM_PROPERTY = "scim";
+ static final String MANAGED_INSTANCE_PROPERTY = "managedInstanceInformation";
private static final String LANGUAGE_PROPERTY = "language";
+ private static final String VERSION = "version";
private final List<TelemetryExtension> extensions;
this.system2 = system2;
}
- public void writeTelemetryData(JsonWriter json, TelemetryData statistics) {
+ public void writeTelemetryData(JsonWriter json, TelemetryData telemetryData) {
json.beginObject();
- json.prop("id", statistics.getServerId());
- json.prop("version", statistics.getVersion());
- json.prop("messageSequenceNumber", statistics.getMessageSequenceNumber());
+ json.prop("id", telemetryData.getServerId());
+ json.prop(VERSION, telemetryData.getVersion());
+ json.prop("messageSequenceNumber", telemetryData.getMessageSequenceNumber());
json.prop("localTimestamp", toUtc(system2.now()));
- statistics.getEdition().ifPresent(e -> json.prop("edition", e.name().toLowerCase(Locale.ENGLISH)));
- json.prop("defaultQualityGate", statistics.getDefaultQualityGate());
+ telemetryData.getEdition().ifPresent(e -> json.prop("edition", e.name().toLowerCase(Locale.ENGLISH)));
+ json.prop("defaultQualityGate", telemetryData.getDefaultQualityGate());
json.name("database");
json.beginObject();
- json.prop("name", statistics.getDatabase().name());
- json.prop("version", statistics.getDatabase().version());
+ json.prop("name", telemetryData.getDatabase().name());
+ json.prop(VERSION, telemetryData.getDatabase().version());
json.endObject();
json.name("plugins");
json.beginArray();
- statistics.getPlugins().forEach((plugin, version) -> {
+ telemetryData.getPlugins().forEach((plugin, version) -> {
json.beginObject();
json.prop("name", plugin);
- json.prop("version", version);
+ json.prop(VERSION, version);
json.endObject();
});
json.endArray();
- if (!statistics.getCustomSecurityConfigs().isEmpty()) {
+ if (!telemetryData.getCustomSecurityConfigs().isEmpty()) {
json.name("customSecurityConfig");
json.beginArray();
- json.values(statistics.getCustomSecurityConfigs());
+ json.values(telemetryData.getCustomSecurityConfigs());
json.endArray();
}
- statistics.hasUnanalyzedC().ifPresent(hasUnanalyzedC -> json.prop("hasUnanalyzedC", hasUnanalyzedC));
- statistics.hasUnanalyzedCpp().ifPresent(hasUnanalyzedCpp -> json.prop("hasUnanalyzedCpp", hasUnanalyzedCpp));
+ telemetryData.hasUnanalyzedC().ifPresent(hasUnanalyzedC -> json.prop("hasUnanalyzedC", hasUnanalyzedC));
+ telemetryData.hasUnanalyzedCpp().ifPresent(hasUnanalyzedCpp -> json.prop("hasUnanalyzedCpp", hasUnanalyzedCpp));
- if (statistics.getInstallationDate() != null) {
- json.prop("installationDate", toUtc(statistics.getInstallationDate()));
+ if (telemetryData.getInstallationDate() != null) {
+ json.prop("installationDate", toUtc(telemetryData.getInstallationDate()));
}
- if (statistics.getInstallationVersion() != null) {
- json.prop("installationVersion", statistics.getInstallationVersion());
+ if (telemetryData.getInstallationVersion() != null) {
+ json.prop("installationVersion", telemetryData.getInstallationVersion());
}
- json.prop("docker", statistics.isInDocker());
-
- json.prop(SCIM_PROPERTY, statistics.isScimEnabled());
-
- writeUserData(json, statistics);
- writeProjectData(json, statistics);
- writeProjectStatsData(json, statistics);
- writeQualityGates(json, statistics);
+ json.prop("docker", telemetryData.isInDocker());
+ writeUserData(json, telemetryData);
+ writeProjectData(json, telemetryData);
+ writeProjectStatsData(json, telemetryData);
+ writeQualityGates(json, telemetryData);
+ writeManagedInstanceInformation(json, telemetryData.getManagedInstanceInformation());
extensions.forEach(e -> e.write(json));
json.endObject();
}
- private static void writeUserData(JsonWriter json, TelemetryData statistics) {
- if (statistics.getUserTelemetries() != null) {
+ private static void writeUserData(JsonWriter json, TelemetryData telemetryData) {
+ if (telemetryData.getUserTelemetries() != null) {
json.name("users");
json.beginArray();
- statistics.getUserTelemetries().forEach(user -> {
+ telemetryData.getUserTelemetries().forEach(user -> {
json.beginObject();
json.prop("userUuid", DigestUtils.sha3_224Hex(user.getUuid()));
json.prop("status", user.isActive() ? "active" : "inactive");
}
}
- private static void writeProjectData(JsonWriter json, TelemetryData statistics) {
- if (statistics.getProjects() != null) {
+ private static void writeProjectData(JsonWriter json, TelemetryData telemetryData) {
+ if (telemetryData.getProjects() != null) {
json.name("projects");
json.beginArray();
- statistics.getProjects().forEach(project -> {
+ telemetryData.getProjects().forEach(project -> {
json.beginObject();
json.prop("projectUuid", project.projectUuid());
if (project.lastAnalysis() != null) {
}
}
- private static void writeProjectStatsData(JsonWriter json, TelemetryData statistics) {
- if (statistics.getProjectStatistics() != null) {
+ private static void writeProjectStatsData(JsonWriter json, TelemetryData telemetryData) {
+ if (telemetryData.getProjectStatistics() != null) {
json.name("projects-general-stats");
json.beginArray();
- statistics.getProjectStatistics().forEach(project -> {
+ telemetryData.getProjectStatistics().forEach(project -> {
json.beginObject();
json.prop("projectUuid", project.getProjectUuid());
json.prop("branchCount", project.getBranchCount());
}
}
- private static void writeQualityGates(JsonWriter json, TelemetryData statistics) {
- if (statistics.getQualityGates() != null) {
+ private static void writeQualityGates(JsonWriter json, TelemetryData telemetryData) {
+ if (telemetryData.getQualityGates() != null) {
json.name("quality-gates");
json.beginArray();
- statistics.getQualityGates().forEach(qualityGate -> {
+ telemetryData.getQualityGates().forEach(qualityGate -> {
json.beginObject();
json.prop("uuid", qualityGate.uuid());
json.prop("caycStatus", qualityGate.caycStatus());
}
}
+ private static void writeManagedInstanceInformation(JsonWriter json, TelemetryData.ManagedInstanceInformation provider) {
+ json.name(MANAGED_INSTANCE_PROPERTY);
+ json.beginObject();
+ json.prop("isManaged", provider.isManaged());
+ json.prop("provider", provider.isManaged() ? provider.provider() : null);
+ json.endObject();
+ }
+
@NotNull
private static String toUtc(long date) {
return DateTimeFormatter.ofPattern(DATETIME_FORMAT)
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.user.UserTelemetryDto;
-import static java.lang.String.format;
import static java.util.stream.Collectors.joining;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import static org.sonar.server.telemetry.TelemetryDataJsonWriter.SCIM_PROPERTY;
import static org.sonar.test.JsonAssert.assertJson;
@RunWith(DataProviderRunner.class)
""".formatted(isInDocker));
}
+ @DataProvider
+ public static Object[][] getManagedInstanceData() {
+ return new Object[][] {
+ {true, "scim"},
+ {true, "github"},
+ {true, "gitlab"},
+ {false, null},
+ };
+ }
+
@Test
- @UseDataProvider("getFeatureFlagEnabledStates")
- public void write_scim_feature_flag(boolean isScimEnabled) {
+ @UseDataProvider("getManagedInstanceData")
+ public void writeTelemetryData_encodesCorrectlyManagedInstanceInformation(boolean isManaged, String provider) {
TelemetryData data = telemetryBuilder()
- .setIsScimEnabled(isScimEnabled)
+ .setManagedInstanceInformation(new TelemetryData.ManagedInstanceInformation(isManaged, provider))
.build();
String json = writeTelemetryData(data);
- assertJson(json).isSimilarTo("{" + format(" \"%s\":", SCIM_PROPERTY) + isScimEnabled + "}");
+ if (isManaged) {
+ assertJson(json).isSimilarTo("""
+ {
+ "managedInstanceInformation": {
+ "isManaged": true,
+ "provider": "%s"
+ }
+ }
+ """.formatted(provider));
+ } else {
+ assertJson(json).isSimilarTo("""
+ {
+ "managedInstanceInformation": {
+ "isManaged": false
+ }
+ }
+ """);
+ }
}
@Test
.setVersion("bar")
.setMessageSequenceNumber(1L)
.setPlugins(Collections.emptyMap())
+ .setManagedInstanceInformation(new TelemetryData.ManagedInstanceInformation(false, null))
.setDatabase(new TelemetryData.Database("H2", "11"));
}
@DataProvider
public static Object[][] allEditions() {
return Arrays.stream(EditionProvider.Edition.values())
- .map(t -> new Object[]{t})
+ .map(t -> new Object[] {t})
.toArray(Object[][]::new);
}
import org.sonar.db.metric.MetricDto;
import org.sonar.db.qualitygate.ProjectQgateAssociationDto;
import org.sonar.db.qualitygate.QualityGateDto;
+import org.sonar.server.management.ManagedInstanceService;
import org.sonar.server.platform.DockerSupport;
import org.sonar.server.property.InternalProperties;
import org.sonar.server.qualitygate.QualityGateCaycChecker;
private final DockerSupport dockerSupport;
private final QualityGateCaycChecker qualityGateCaycChecker;
private final QualityGateFinder qualityGateFinder;
+ private final ManagedInstanceService managedInstanceService;
@Inject
public TelemetryDataLoaderImpl(Server server, DbClient dbClient, PluginRepository pluginRepository,
PlatformEditionProvider editionProvider, InternalProperties internalProperties, Configuration configuration,
- DockerSupport dockerSupport, QualityGateCaycChecker qualityGateCaycChecker, QualityGateFinder qualityGateFinder) {
+ DockerSupport dockerSupport, QualityGateCaycChecker qualityGateCaycChecker, QualityGateFinder qualityGateFinder,
+ ManagedInstanceService managedInstanceService) {
this.server = server;
this.dbClient = dbClient;
this.pluginRepository = pluginRepository;
this.dockerSupport = dockerSupport;
this.qualityGateCaycChecker = qualityGateCaycChecker;
this.qualityGateFinder = qualityGateFinder;
+ this.managedInstanceService = managedInstanceService;
}
private static Database loadDatabaseMetadata(DbSession dbSession) {
installationDateProperty.ifPresent(s -> data.setInstallationDate(Long.valueOf(s)));
Optional<String> installationVersionProperty = internalProperties.read(InternalProperties.INSTALLATION_VERSION);
+
return data
.setInstallationVersion(installationVersionProperty.orElse(null))
.setInDocker(dockerSupport.isRunningInDocker())
- .setIsScimEnabled(isScimEnabled())
+ .setManagedInstanceInformation(buildManagedInstanceInformation())
.build();
}
+
private void resolveUnanalyzedLanguageCode(TelemetryData.Builder data, DbSession dbSession) {
long numberOfUnanalyzedCMeasures = dbClient.liveMeasureDao().countProjectsHavingMeasure(dbSession, UNANALYZED_C_KEY);
long numberOfUnanalyzedCppMeasures = dbClient.liveMeasureDao().countProjectsHavingMeasure(dbSession, UNANALYZED_CPP_KEY);
private boolean isScimEnabled() {
return this.internalProperties.read(SCIM_PROPERTY_ENABLED).map(Boolean::parseBoolean).orElse(false);
}
+
+ private TelemetryData.ManagedInstanceInformation buildManagedInstanceInformation() {
+ String provider = managedInstanceService.isInstanceExternallyManaged() ? managedInstanceService.getProviderName() : null;
+ return new TelemetryData.ManagedInstanceInformation(managedInstanceService.isInstanceExternallyManaged(), provider);
+ }
+
}
import org.sonar.db.user.UserDbTester;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserTelemetryDto;
+import org.sonar.server.management.ManagedInstanceService;
import org.sonar.server.platform.DockerSupport;
import org.sonar.server.property.InternalProperties;
import org.sonar.server.property.MapInternalProperties;
import static org.sonar.server.metric.UnanalyzedLanguageMetrics.UNANALYZED_CPP_KEY;
import static org.sonar.server.metric.UnanalyzedLanguageMetrics.UNANALYZED_C_KEY;
import static org.sonar.server.qualitygate.QualityGateCaycStatus.NON_COMPLIANT;
-import static org.sonar.server.telemetry.TelemetryDataLoaderImpl.SCIM_PROPERTY_ENABLED;
@RunWith(DataProviderRunner.class)
public class TelemetryDataLoaderImplTest {
private final QualityGateCaycChecker qualityGateCaycChecker = mock(QualityGateCaycChecker.class);
private final QualityGateFinder qualityGateFinder = new QualityGateFinder(db.getDbClient());
private final InternalProperties internalProperties = spy(new MapInternalProperties());
+ private final ManagedInstanceService managedInstanceService = mock(ManagedInstanceService.class);
private final TelemetryDataLoader communityUnderTest = new TelemetryDataLoaderImpl(server, db.getDbClient(), pluginRepository, editionProvider,
- internalProperties, configuration, dockerSupport, qualityGateCaycChecker, qualityGateFinder);
+ internalProperties, configuration, dockerSupport, qualityGateCaycChecker, qualityGateFinder, managedInstanceService);
private final TelemetryDataLoader commercialUnderTest = new TelemetryDataLoaderImpl(server, db.getDbClient(), pluginRepository, editionProvider,
- internalProperties, configuration, dockerSupport, qualityGateCaycChecker, qualityGateFinder);
+ internalProperties, configuration, dockerSupport, qualityGateCaycChecker, qualityGateFinder, managedInstanceService);
private QualityGateDto builtInDefaultQualityGate;
private MetricDto bugsDto;
}
@Test
- @UseDataProvider("getScimFeatureStatues")
- public void detect_scim_feature_status(String isEnabled) {
- db.components().insertPublicProject().getMainBranchComponent();
- when(internalProperties.read(SCIM_PROPERTY_ENABLED)).thenReturn(Optional.ofNullable(isEnabled));
+ @UseDataProvider("getManagedInstanceData")
+ public void managedInstanceData_containsCorrectInformation(boolean isManaged, String provider) {
+ when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(isManaged);
+ when(managedInstanceService.getProviderName()).thenReturn(provider);
- TelemetryData data = communityUnderTest.load();
+ TelemetryData data = commercialUnderTest.load();
- assertThat(data.isScimEnabled()).isEqualTo(Boolean.parseBoolean(isEnabled));
+ TelemetryData.ManagedInstanceInformation managedInstance = data.getManagedInstanceInformation();
+ assertThat(managedInstance.isManaged()).isEqualTo(isManaged);
+ assertThat(managedInstance.provider()).isEqualTo(provider);
}
@Test
result.add(null);
return result;
}
+
+ @DataProvider
+ public static Object[][] getManagedInstanceData() {
+ return new Object[][]{
+ {true, "scim"},
+ {true, "github"},
+ {true, "gitlab"},
+ {false, null},
+ };
+ }
}