private final boolean usingBranches;
private final Database database;
private final Map<String, Long> projectCountByLanguage;
+ private final Map<String, Long> almIntegrationCountByAlm;
private final Map<String, Long> nclocByLanguage;
private final EditionProvider.Edition edition;
private final String licenseType;
usingBranches = builder.usingBranches;
database = builder.database;
projectCountByLanguage = builder.projectMeasuresStatistics.getProjectCountByLanguage();
+ almIntegrationCountByAlm = builder.almIntegrationCountByAlm;
nclocByLanguage = builder.projectMeasuresStatistics.getNclocByLanguage();
edition = builder.edition;
licenseType = builder.licenseType;
return projectCountByLanguage;
}
+ public Map<String, Long> getAlmIntegrationCountByAlm() {
+ return almIntegrationCountByAlm;
+ }
+
public Map<String, Long> getNclocByLanguage() {
return nclocByLanguage;
}
private Map<String, String> plugins;
private Database database;
private ProjectMeasuresStatistics projectMeasuresStatistics;
+ private Map<String, Long> almIntegrationCountByAlm;
private Long ncloc;
private Boolean usingBranches;
private EditionProvider.Edition edition;
return this;
}
+ Builder setAlmIntegrationCountByAlm(Map<String, Long> almIntegrationCountByAlm) {
+ this.almIntegrationCountByAlm = almIntegrationCountByAlm;
+ return this;
+ }
+
Builder setProjectMeasuresStatistics(ProjectMeasuresStatistics projectMeasuresStatistics) {
this.projectMeasuresStatistics = projectMeasuresStatistics;
return this;
requireNonNull(version);
requireNonNull(plugins);
requireNonNull(projectMeasuresStatistics);
+ requireNonNull(almIntegrationCountByAlm);
requireNonNull(ncloc);
requireNonNull(database);
requireNonNull(usingBranches);
json.endObject();
});
json.endArray();
+ json.name("almIntegrationCount");
+ json.beginArray();
+ statistics.getAlmIntegrationCountByAlm().forEach((alm, count) -> {
+ json.beginObject();
+ json.prop("alm", alm);
+ json.prop("count", count);
+ json.endObject();
+ });
+ json.endArray();
+
statistics.hasUnanalyzedC().ifPresent(hasUnanalyzedC -> json.prop("hasUnanalyzedC", hasUnanalyzedC));
statistics.hasUnanalyzedCpp().ifPresent(hasUnanalyzedCpp -> json.prop("hasUnanalyzedCpp", hasUnanalyzedCpp));
if (statistics.getInstallationDate() != null) {
*/
package org.sonar.server.telemetry;
+import com.google.common.collect.ImmutableMap;
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
.setServerId("foo")
.setVersion("bar")
.setPlugins(Collections.emptyMap())
+ .setAlmIntegrationCountByAlm(Collections.emptyMap())
.setProjectMeasuresStatistics(ProjectMeasuresStatistics.builder()
.setProjectCount(12)
.setProjectCountByLanguage(Collections.emptyMap())
"}");
}
+ @Test
+ public void write_alm_count_by_alm() {
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setAlmIntegrationCountByAlm(ImmutableMap.of(
+ "github", 4L,
+ "github_cloud", 1L,
+ "gitlab", 2L,
+ "gitlab_cloud", 5L,
+ "azure_devops", 1L))
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"almIntegrationCount\": " +
+ "["
+ + "{ \"alm\":\"github\", \"count\":4},"
+ + "{ \"alm\":\"github_cloud\", \"count\":1},"
+ + "{ \"alm\":\"gitlab\", \"count\":2},"
+ + "{ \"alm\":\"gitlab_cloud\", \"count\":5},"
+ + "{ \"alm\":\"azure_devops\", \"count\":1},"
+ + "]"
+ +
+ "}");
+ }
+
@Test
public void does_not_write_installation_date_if_null() {
TelemetryData data = SOME_TELEMETRY_DATA
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
+import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.platform.Server;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
+import org.sonar.db.alm.setting.ALM;
+import org.sonar.db.alm.setting.AlmSettingDto;
import org.sonar.db.measure.SumNclocDbQuery;
import org.sonar.server.es.SearchOptions;
import org.sonar.server.measure.index.ProjectMeasuresIndex;
import org.sonar.server.user.index.UserQuery;
import static java.util.Optional.ofNullable;
+import static org.apache.commons.lang.StringUtils.startsWith;
import static org.sonar.core.platform.EditionProvider.Edition.COMMUNITY;
import static org.sonar.server.metric.UnanalyzedLanguageMetrics.UNANALYZED_CPP_KEY;
import static org.sonar.server.metric.UnanalyzedLanguageMetrics.UNANALYZED_C_KEY;
data.setHasUnanalyzedC(numberOfUnanalyzedCMeasures > 0);
data.setHasUnanalyzedCpp(numberOfUnanalyzedCppMeasures > 0);
});
+
+ data.setAlmIntegrationCountByAlm(countAlmUsage(dbSession));
}
Optional<String> installationDateProperty = internalProperties.read(InternalProperties.INSTALLATION_DATE);
installationDateProperty.ifPresent(s -> data.setInstallationDate(Long.valueOf(s)));
return data.build();
}
+ private Map<String, Long> countAlmUsage(DbSession dbSession) {
+ return dbClient.almSettingDao().selectAll(dbSession).stream()
+ .collect(Collectors.groupingBy(almSettingDto -> {
+ if (checkIfCloudAlm(almSettingDto, ALM.GITHUB, "https://api.github.com")) {
+ return "github_cloud";
+ } else if (checkIfCloudAlm(almSettingDto, ALM.GITLAB, "https://gitlab.com/api/v4")) {
+ return "gitlab_cloud";
+ } else if (checkIfCloudAlm(almSettingDto, ALM.AZURE_DEVOPS, "https://dev.azure.com")) {
+ return "azure_devops_cloud";
+ } else if (ALM.BITBUCKET_CLOUD.equals(almSettingDto.getAlm())) {
+ return almSettingDto.getRawAlm();
+ }
+ return almSettingDto.getRawAlm() + "_server";
+ }, Collectors.counting()));
+ }
+
+ private static boolean checkIfCloudAlm(AlmSettingDto almSettingDto, ALM alm, String url) {
+ return alm.equals(almSettingDto.getAlm()) && startsWith(almSettingDto.getUrl(), url);
+ }
+
@Override
public String loadServerId() {
return server.getId();
+ "\"Search Nodes\":[{\"Name\":\"searchNodes\",\"\":{\"name\":\"searchNodes\"}}],"
+ "\"Statistics\":{\"id\":\"\",\"version\":\"\",\"database\":{\"name\":\"\",\"version\":\"\"},\"plugins\":[],"
+ "\"userCount\":0,\"projectCount\":0,\"usingBranches\":false,\"ncloc\":0,\"projectCountByLanguage\":[]," +
- "\"nclocByLanguage\":[],\"installationDate\":0,\"installationVersion\":\"\",\"docker\":false}}");
+ "\"nclocByLanguage\":[],\"almIntegrationCount\":[],\"installationDate\":0,\"installationVersion\":\"\",\"docker\":false}}");
}
private static NodeInfo createNodeInfo(String name) {
// response does not contain empty "Section Three"
assertThat(writer.toString()).isEqualTo("{\"Health\":\"GREEN\",\"Health Causes\":[],\"Section One\":{\"foo\":\"bar\"},\"Section Two\":{\"one\":1,\"two\":2}," +
"\"Statistics\":{\"id\":\"\",\"version\":\"\",\"database\":{\"name\":\"\",\"version\":\"\"},\"plugins\":[],\"userCount\":0,\"projectCount\":0,\"usingBranches\":false," +
- "\"ncloc\":0,\"projectCountByLanguage\":[],\"nclocByLanguage\":[],\"installationDate\":0,\"installationVersion\":\"\",\"docker\":false}}");
+ "\"ncloc\":0,\"projectCountByLanguage\":[],\"nclocByLanguage\":[],\"almIntegrationCount\":[],\"installationDate\":0,\"installationVersion\":\"\",\"docker\":false}}");
}
private void logInAsSystemAdministrator() {
.setServerId("foo")
.setVersion("bar")
.setPlugins(Collections.emptyMap())
+ .setAlmIntegrationCountByAlm(Collections.emptyMap())
.setProjectMeasuresStatistics(ProjectMeasuresStatistics.builder()
.setProjectCount(12)
.setProjectCountByLanguage(Collections.emptyMap())
db.measures().insertLiveMeasure(project2, nclocDistrib, m -> m.setValue(null).setData("java=300;kotlin=2500"));
projectMeasuresIndexer.indexAll();
+ // alm
+ db.almSettings().insertAzureAlmSetting();
+ db.almSettings().insertAzureAlmSetting(a -> a.setUrl("https://dev.azure.com"));
+ db.almSettings().insertBitbucketAlmSetting();
+ db.almSettings().insertBitbucketCloudAlmSetting();
+ db.almSettings().insertGitHubAlmSetting();
+ db.almSettings().insertGitHubAlmSetting(a -> a.setUrl("https://api.github.com"));
+ db.almSettings().insertGitlabAlmSetting();
+ db.almSettings().insertGitlabAlmSetting(a -> a.setUrl("https://gitlab.com/api/v4"));
+
TelemetryData data = communityUnderTest.load();
assertThat(data.getServerId()).isEqualTo(serverId);
assertThat(data.getVersion()).isEqualTo(version);
assertThat(data.getNclocByLanguage()).containsOnly(
entry("java", 500L), entry("kotlin", 2500L), entry("js", 50L));
assertThat(data.isInDocker()).isFalse();
+ assertThat(data.getAlmIntegrationCountByAlm())
+ .containsEntry("azure_devops_server", 1L)
+ .containsEntry("azure_devops_cloud", 1L)
+ .containsEntry("bitbucket_server", 1L)
+ .containsEntry("bitbucket_cloud", 1L)
+ .containsEntry("gitlab_server", 1L)
+ .containsEntry("gitlab_cloud", 1L)
+ .containsEntry("github_cloud", 1L)
+ .containsEntry("github_server", 1L);
}
private void assertDatabaseMetadata(TelemetryData.Database database) {
.setMediaType(MediaTypes.JSON)).content();
}
+ /**
+ *
+ * This is a POST request.
+ * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/create_bitbucket_cloud">Further information about this action online (including a response example)</a>
+ * @since 8.7
+ */
+ public void createBitbucketCloud(CreateBitbucketCloudRequest request) {
+ call(
+ new PostRequest(path("create_bitbucketcloud"))
+ .setParam("key", request.getKey())
+ .setParam("clientId", request.getClientId())
+ .setParam("clientSecret", request.getClientSecret())
+ .setParam("workspace", request.getWorkspace())
+ .setMediaType(MediaTypes.JSON)).content();
+ }
+
/**
* This is a POST request.
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/create_github">Further information about this action online (including a response example)</a>
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.sonarqube.ws.client.almsettings;
+
+import javax.annotation.Generated;
+
+/**
+ *
+ * This is a POST request.
+ * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/alm_settings/create_bitbucket_cloud">Further information about this action online (including a response example)</a>
+ * @since 8.7
+ */
+@Generated("sonar-ws-generator")
+public class CreateBitbucketCloudRequest {
+
+ private String key;
+ private String clientId;
+ private String clientSecret;
+ private String workspace;
+
+ public String getKey() {
+ return key;
+ }
+
+ /**
+ * This is a mandatory parameter.
+ */
+ public CreateBitbucketCloudRequest setKey(String key) {
+ this.key = key;
+ return this;
+ }
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ /**
+ * This is a mandatory parameter.
+ */
+ public CreateBitbucketCloudRequest setClientId(String clientId) {
+ this.clientId = clientId;
+ return this;
+ }
+
+ public String getClientSecret() {
+ return clientSecret;
+ }
+
+ /**
+ * This is a mandatory parameter.
+ */
+ public CreateBitbucketCloudRequest setClientSecret(String clientSecret) {
+ this.clientSecret = clientSecret;
+ return this;
+ }
+
+ public String getWorkspace() {
+ return workspace;
+ }
+
+ /**
+ * This is a mandatory parameter.
+ */
+ public CreateBitbucketCloudRequest setWorkspace(String workspace) {
+ this.workspace = workspace;
+ return this;
+ }
+}