io.qameta.allure.ga.GaPlugin Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of allure-generator Show documentation
Show all versions of allure-generator Show documentation
Module allure-generator of Allure Framework.
/*
* Copyright 2016-2024 Qameta Software Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.qameta.allure.ga;
import com.fasterxml.jackson.databind.json.JsonMapper;
import io.qameta.allure.Aggregator2;
import io.qameta.allure.ReportStorage;
import io.qameta.allure.core.Configuration;
import io.qameta.allure.core.LaunchResults;
import io.qameta.allure.entity.ExecutorInfo;
import io.qameta.allure.entity.Label;
import io.qameta.allure.entity.LabelName;
import io.qameta.allure.executor.ExecutorPlugin;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import static io.qameta.allure.Constants.NO_ANALYTICS;
/**
* @author charlie (Dmitry Baev).
*/
@SuppressWarnings({"PMD.ExcessiveImports"})
public class GaPlugin implements Aggregator2 {
private static final Logger LOGGER = LoggerFactory.getLogger(GaPlugin.class);
private static final String LOCAL = "local";
private static final String GA_ENDPOINT_FORMAT
= "https://www.google-analytics.com/mp/collect?measurement_id=%s&api_secret=%s";
private static final String MEASUREMENT_ID = "G-FVWC4GKEYS";
private static final String GA_SECRET = "rboZz0HySdmCVIvtydmSTQ";
private static final String GA_EVENT_NAME = "report_generated";
@Override
public void aggregate(final Configuration configuration,
final List launchesResults,
final ReportStorage storage) {
if (Objects.nonNull(System.getenv(NO_ANALYTICS))) {
LOGGER.debug("analytics is disabled");
return;
}
LOGGER.debug("send analytics");
final GaParameters parameters = new GaParameters()
.setReportUuid(configuration.getUuid())
.setAllureVersion(configuration.getVersion())
.setExecutorType(getExecutorType(launchesResults))
.setResultsCount(getTestResultsCount(launchesResults))
.setResultsFormat(getLabelValuesAsString(launchesResults, LabelName.RESULT_FORMAT))
.setFramework(getLabelValuesAsString(launchesResults, LabelName.FRAMEWORK))
.setLanguage(getLabelValuesAsString(launchesResults, LabelName.LANGUAGE));
final String cid = getClientId(launchesResults);
try {
CompletableFuture
.runAsync(() -> sendStats(cid, parameters))
.get(10, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
LOGGER.debug("Could not send analytics within 10 seconds", e);
}
}
protected void sendStats(final String clientId, final GaParameters parameters) {
final HttpClientBuilder builder = HttpClientBuilder.create();
try (CloseableHttpClient client = builder.build()) {
final String uri = String.format(
GA_ENDPOINT_FORMAT,
MEASUREMENT_ID, GA_SECRET
);
final HttpPost post = new HttpPost(uri);
final String stringBody = new JsonMapper().writeValueAsString(
new GaRequest()
.setClientId(clientId)
.setEvents(Collections.singletonList(new GaEvent()
.setName(GA_EVENT_NAME)
.setParams(parameters)
))
);
final StringEntity entity = new StringEntity(
stringBody,
ContentType.APPLICATION_JSON.withCharset(StandardCharsets.UTF_8)
);
post.setEntity(entity);
client.execute(post).close();
LOGGER.debug("GA done");
} catch (IOException e) {
LOGGER.debug("Could not send analytics", e);
}
}
private static String getClientId(final List launchesResults) {
return ExecutorPlugin.getLatestExecutor(launchesResults)
.map(ExecutorInfo::getBuildUrl)
.flatMap(GaPlugin::getHostSafe)
.map(DigestUtils::sha256Hex)
.orElseGet(() -> getLocalHostName()
.map(DigestUtils::sha256Hex)
.orElse(UUID.randomUUID().toString())
);
}
private static Optional getHostSafe(final String url) {
try {
return Optional.of(URI.create(url))
.map(URI::getHost);
} catch (Exception e) {
LOGGER.debug("invalid build url", e);
}
return Optional.empty();
}
/* package-private */
static String getExecutorType(final List launchesResults) {
return ExecutorPlugin.getLatestExecutor(launchesResults)
.map(ExecutorInfo::getType)
.map(String::trim)
.map(String::toLowerCase)
.orElse(LOCAL);
}
private static long getTestResultsCount(final List launchesResults) {
return launchesResults.stream()
.map(LaunchResults::getResults)
.mapToLong(Collection::size)
.sum();
}
private static String getLabelValuesAsString(final List launchesResults,
final LabelName labelName) {
final String values = launchesResults.stream()
.flatMap(results -> results.getResults().stream())
.flatMap(result -> result.getLabels().stream())
.filter(label -> labelName.value().equals(label.getName()))
.map(Label::getValue)
.distinct()
.sorted()
.collect(Collectors.joining(" "))
.toLowerCase();
return values.isEmpty() ? "Undefined" : values;
}
private static Optional getLocalHostName() {
try {
return Optional.ofNullable(InetAddress.getLocalHost().getHostName());
} catch (UnknownHostException e) {
LOGGER.debug("Could not get host name", e);
return Optional.empty();
}
}
}