Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor of Jira Export Plugin #1086

Merged
merged 11 commits into from
Jun 3, 2020
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2019 Qameta Software OÜ
*
* 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.jira;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.experimental.Accessors;

/**
* Jira launch result export data.
*/
@Data
@Accessors(chain = true)
@JsonIgnoreProperties(ignoreUnknown = true)
public class JiraExportResult {
private String issueKey;
private String externalId;
private String status;
@JsonInclude(JsonInclude.Include.NON_NULL)
private String message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,12 @@
@Accessors(chain = true)
@JsonIgnoreProperties(ignoreUnknown = true)
public class JiraLaunch {

private String externalId;

private List<String> issueKeys;

private List<LaunchStatisticExport> statistic;
private String name;
private String url;
private Long date;

private Long failed;
private Long broken;
private Long passed;
private Long skipped;
private Long unknown;


}
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,21 @@ public interface JiraService {
Response<ResponseBody> createIssueComment(@Path("issueKey") String issueKey, @Body JiraIssueComment comment);

@POST("allure/1.0/launch")
JiraLaunch createJiraLaunch(@Body JiraLaunch launch);
List<JiraExportResult> createJiraLaunch(@Body JiraLaunch launch, @Query("issueKey") List<String> issueKey);

@GET("allure/1.0/launch")
List<JiraLaunch> getJiraLaunches(@Query("issueKey") String issueKey);

@POST("allure/1.0/testresult")
JiraTestResult createTestResult(@Body JiraTestResult launch);
List<JiraExportResult> createTestResult(@Body JiraTestResult launch, @Query("issueKey") List<String> issueKey);

@GET("allure/1.0/testresult")
List<JiraTestResult> getTestResults(@Query("issueKey") String issueKey);

@GET("raven/1.0/api/testexec/{issueKey}/test")
List<XrayTestRun> getTestRunsForTestExecution(@Path("issueKey") String issueKey);

@PUT("raven/1.0/api/testrun/{id}/status")
Response<ResponseBody> updateTestRunStatus(@Path("id") Integer id, @Query("status") String status);
@PUT("raven/1.0/api/testrun/{externalId}/status")
Response<ResponseBody> updateTestRunStatus(@Path("externalId") Integer externalId, @Query("status") String status);

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,22 @@
import lombok.Data;
import lombok.experimental.Accessors;

import java.util.List;

/**
* Jira test result export data.
*/
@Data
@Accessors(chain = true)
@JsonIgnoreProperties(ignoreUnknown = true)
public class JiraTestResult {

private int id;

private String externalId;
private List<String> issueKeys;

private String testCaseId;
private String historyKey;
private String name;
private String url;
private Long date;

private String status;

private String color;
private Long date;
private String launchExternalId;
private String launchName;
private String launchUrl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2019 Qameta Software OÜ
*
* 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.jira;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import lombok.experimental.Accessors;

/**
* Statistics for Jira test result export data.
*/

@Data
@Accessors(chain = true)
@JsonIgnoreProperties(ignoreUnknown = true)
public class LaunchStatisticExport {
private final String status;
private final String color;
private final long count;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.qameta.allure.jira;

import io.qameta.allure.entity.Status;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.experimental.Accessors;

/**
* Mutable Test Results Enum for Jira Integration.
*/

@AllArgsConstructor
@Accessors(fluent = true)
@Getter
public enum ResultStatus {
FAILED(Status.FAILED, "f90602"),
BROKEN(Status.BROKEN, "febe0d"),
PASSED(Status.PASSED, "78b63c"),
SKIPPED(Status.SKIPPED, "888888"),
UNKNOWN(Status.UNKNOWN, "bf34a6");


private final Status statusName;
private final String color;


}
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,11 @@
import io.qameta.allure.Aggregator;
import io.qameta.allure.core.Configuration;
import io.qameta.allure.core.LaunchResults;
import io.qameta.allure.entity.ExecutorInfo;
import io.qameta.allure.entity.Link;
import io.qameta.allure.entity.Statistic;
import io.qameta.allure.entity.TestResult;
import io.qameta.allure.entity.*;
baev marked this conversation as resolved.
Show resolved Hide resolved
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
Expand All @@ -38,12 +33,12 @@
/**
* @author eroshenkoam (Artem Eroshenko).
*/


public class JiraExportPlugin implements Aggregator {

private static final Logger LOGGER = LoggerFactory.getLogger(JiraExportPlugin.class);

private static final String EXECUTORS_BLOCK_NAME = "executor";

private static final String ALLURE_JIRA_ENABLED = "ALLURE_JIRA_ENABLED";
private static final String ALLURE_JIRA_LAUNCH_ISSUES = "ALLURE_JIRA_LAUNCH_ISSUES";

Expand Down Expand Up @@ -74,124 +69,89 @@ public void aggregate(final Configuration configuration,
if (enabled) {
final JiraService jiraService = jiraServiceSupplier.get();

final List<String> issues = splitByComma(this.issues);
final ExecutorInfo executor = getExecutor(launchesResults);
final Statistic statistic = getStatistic(launchesResults);

final JiraLaunch launch = getJiraLaunch(issues, executor, statistic);
final JiraLaunch created = exportLaunchToJira(jiraService, launch);
final List<String> issues = JiraExportUtility.splitByComma(this.issues);
final ExecutorInfo executor = JiraExportUtility.getExecutor(launchesResults);
final Statistic statisticToConvert = JiraExportUtility.getStatistic(launchesResults);
final List<LaunchStatisticExport> statistic = JiraExportUtility.convertStatistics(statisticToConvert);
final JiraLaunch launch = JiraExportUtility.getJiraLaunch(executor, statistic);
exportLaunchToJira(jiraService, launch, issues);

getTestResults(launchesResults).stream()
.map(testResult -> getJiraTestResult(created, executor, testResult))
JiraExportUtility.getTestResults(launchesResults).stream()
.map(testResult -> JiraExportUtility.getJiraTestResult(executor, testResult))
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(testResult -> exportTestResultToJira(jiraService, testResult));
.forEach(jiraTestResult -> {
JiraExportUtility.getTestResults(launchesResults)
.stream()
.forEach(testResult ->
exportTestResultToJira(jiraService, jiraTestResult, testResult));
});
}
}

private JiraLaunch getJiraLaunch(final List<String> issueKeys,
final ExecutorInfo executor,
final Statistic statistic) {
return new JiraLaunch()
.setIssueKeys(issueKeys)
.setName(executor.getBuildName())
.setUrl(executor.getReportUrl())
.setPassed(statistic.getPassed())
.setFailed(statistic.getFailed())
.setBroken(statistic.getBroken())
.setSkipped(statistic.getSkipped())
.setUnknown(statistic.getUnknown())
.setDate(System.currentTimeMillis());
}

private Optional<JiraTestResult> getJiraTestResult(final JiraLaunch launch,
final ExecutorInfo executor,
final TestResult testResult) {
final List<String> issues = testResult.getLinks().stream()
.filter(this::isIssueLink)
.map(Link::getName)
.collect(Collectors.toList());

if (issues.isEmpty()) {
return Optional.empty();
} else {
final JiraTestResult jiraTestResult = new JiraTestResult()
.setIssueKeys(issues)
.setName(testResult.getName())
.setUrl(getJiraTestResultUrl(executor.getReportUrl(), testResult.getUid()))
.setStatus(testResult.getStatus().toString())
.setDate(testResult.getTime().getStop())
.setExternalId(launch.getExternalId());
return Optional.of(jiraTestResult);
}
}


private List<TestResult> getTestResults(final List<LaunchResults> launchesResults) {
return launchesResults.stream()
.map(LaunchResults::getAllResults)
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
private List<JiraExportResult> exportLaunchToJira(final JiraService jiraService,
final JiraLaunch launch,
final List<String> issues) {
try {
final List<JiraExportResult> created = jiraService.createJiraLaunch(launch, issues);

private ExecutorInfo getExecutor(final List<LaunchResults> launchesResults) {
return launchesResults.stream()
.map(launchResults -> launchResults.getExtra(EXECUTORS_BLOCK_NAME))
.filter(Optional::isPresent)
.map(Optional::get)
.filter(ExecutorInfo.class::isInstance)
.map(ExecutorInfo.class::cast)
.findFirst()
.orElse(new ExecutorInfo());
}
final List<JiraExportResult> failedExports = findFailuresInExportResult(created);

private Statistic getStatistic(final List<LaunchResults> launchesResults) {
final Statistic statistic = new Statistic();
launchesResults.stream()
.map(LaunchResults::getAllResults)
.flatMap(Collection::stream)
.forEach(statistic::update);
return statistic;
}
if (!failedExports.isEmpty()) {
logErrorResults(failedExports);
} else {
LOGGER.info(String.format("Allure launch '%s' synced with issues successfully%n",
issues));
LOGGER.info(String.format("Results of launch export %n %s", created));
}

private JiraLaunch exportLaunchToJira(final JiraService jiraService, final JiraLaunch launch) {
try {
final JiraLaunch created = jiraService.createJiraLaunch(launch);
LOGGER.info(String.format("Allure launch '%s' synced with issues '%s' successfully",
created.getExternalId(), created.getIssueKeys()));
return created;
} catch (Throwable e) {
LOGGER.error(String.format("Allure launch sync with issue '%s' error", launch.getIssueKeys()), e);
LOGGER.error(String.format("Allure launch sync with issue '%s' error", issues), e);
throw e;
}
}

private void exportTestResultToJira(final JiraService jiraService, final JiraTestResult testResult) {
private void exportTestResultToJira(final JiraService jiraService,
final JiraTestResult jiraTestResult,
final TestResult testResult) {

if (!jiraTestResult.getTestCaseId().equals(testResult.getUid())) {
baev marked this conversation as resolved.
Show resolved Hide resolved
return;
}

try {
final JiraTestResult created = jiraService.createTestResult(testResult);
LOGGER.info(String.format("Allure test result '%s' synced with issue '%s' successfully",
created.getId(),
created.getIssueKeys()));
final List<String> issues = testResult.getLinks().stream()
.filter(JiraExportUtility::isIssueLink)
.map(Link::getName)
.collect(Collectors.toList());

final List<JiraExportResult> created = jiraService.createTestResult(jiraTestResult, issues);
final List<JiraExportResult> failedExports = findFailuresInExportResult(created);

if (!failedExports.isEmpty()) {
logErrorResults(failedExports);
} else {
LOGGER.info("All Test Results have been successfully exported to Jira");
}

} catch (Throwable e) {
LOGGER.error(String.format("Allure test result sync with issue '%s' failed", testResult.getIssueKeys()), e);
LOGGER.error(String.format("Allure test result sync with issue '%s' failed",
jiraTestResult.getExternalId()), e);
throw e;
}
}


private String getJiraTestResultUrl(final String reportUrl, final String uuid) {
return Optional.ofNullable(reportUrl)
.map(url -> url.endsWith("index.html") ? "%s#testresult/%s" : "%s/#testresult/%s")
.map(pattern -> String.format(pattern, reportUrl, uuid))
.orElse(null);
private void logErrorResults(final List<JiraExportResult> failedExportResults) {
LOGGER.error(String.format("There was an failure in response%n %s", failedExportResults));
}

private boolean isIssueLink(final Link link) {
return "issue".equals(link.getType());
}

private static List<String> splitByComma(final String value) {
return Arrays.asList(value.split(","));
private List<JiraExportResult> findFailuresInExportResult(final List<JiraExportResult> exportResults) {
return exportResults.stream()
.filter(exportResult -> exportResult.getStatus().equals(Status.FAILED.value()))
.collect(Collectors.toList());
}

}
Loading