net.serenitybdd.plugins.jira.JiraUpdater Maven / Gradle / Ivy
package net.serenitybdd.plugins.jira;
import net.serenitybdd.plugins.jira.domain.IssueComment;
import net.serenitybdd.plugins.jira.model.IssueTracker;
import net.serenitybdd.plugins.jira.model.NamedTestResult;
import net.serenitybdd.plugins.jira.model.TestResultComment;
import net.serenitybdd.plugins.jira.service.JIRAConfiguration;
import net.serenitybdd.plugins.jira.service.JIRAInfrastructure;
import net.serenitybdd.plugins.jira.service.NoSuchIssueException;
import net.serenitybdd.plugins.jira.workflow.ClasspathWorkflowLoader;
import net.serenitybdd.plugins.jira.workflow.Workflow;
import net.serenitybdd.plugins.jira.workflow.WorkflowLoader;
import net.thucydides.model.ThucydidesSystemProperty;
import net.thucydides.model.domain.TestOutcomeSummary;
import net.thucydides.model.domain.TestResult;
import net.thucydides.model.util.EnvironmentVariables;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static net.serenitybdd.plugins.jira.JiraPluginConfigurationOptions.*;
import static net.serenitybdd.plugins.jira.model.JIRACommentBuilder.SERENITY_COMMENT_HEADING;
/**
* Class used for JIra interaction, to update comments in Jira issues.
*/
public class JiraUpdater {
static int DEFAULT_MAX_THREADS = 4;
private final IssueTracker issueTracker;
private final EnvironmentVariables environmentVariables;
private static final Logger LOGGER = LoggerFactory.getLogger(JiraUpdater.class);
private final String projectPrefix;
private final Workflow workflow;
private final JIRAConfiguration configuration;
public JiraUpdater(IssueTracker issueTracker,
EnvironmentVariables environmentVariables,
WorkflowLoader loader) {
this.issueTracker = issueTracker;
this.environmentVariables = environmentVariables;
configuration = JIRAInfrastructure.getConfiguration();
workflow = loader.load();
this.projectPrefix = environmentVariables.getProperty(ThucydidesSystemProperty.JIRA_PROJECT.getPropertyName());
logStatus(environmentVariables);
}
private void logStatus(EnvironmentVariables environmentVariables) {
String jiraUrl = environmentVariables.getProperty(ThucydidesSystemProperty.JIRA_URL.getPropertyName());
String reportUrl = ThucydidesSystemProperty.SERENITY_PUBLIC_URL.from(environmentVariables, "");
LOGGER.debug("JIRA LISTENER STATUS");
LOGGER.debug("JIRA URL: {} ", jiraUrl);
LOGGER.debug("REPORT URL: {} ", reportUrl);
LOGGER.debug("WORKFLOW ACTIVE: {} ", workflow.isActive());
}
public void updateIssueStatus(Set issues, final TestResultTally resultTally) {
issues.parallelStream().forEach(
issue -> updateIssue(issue, resultTally.getTestOutcomesForIssue(issue))
);
}
public boolean shouldUpdateIssues() {
if (dryRun()) {
return false;
}
String jiraUrl = environmentVariables.getProperty(ThucydidesSystemProperty.JIRA_URL.getPropertyName());
String reportUrl = ThucydidesSystemProperty.SERENITY_PUBLIC_URL.from(environmentVariables, "");
if (workflow.isActive()) {
LOGGER.debug("WORKFLOW TRANSITIONS: {}", workflow.getTransitions());
}
return !(StringUtils.isEmpty(jiraUrl) || StringUtils.isEmpty(reportUrl));
}
private void updateIssue(String issueId, List testOutcomes) {
try {
TestResultComment testResultComment = newOrUpdatedCommentFor(issueId, testOutcomes);
if (getWorkflow().isActive() && shouldUpdateWorkflow()) {
updateIssueStatusFor(issueId, testResultComment.getOverallResult());
}
} catch (NoSuchIssueException e) {
LOGGER.error("No JIRA issue found with ID {}", issueId);
}
}
private void updateIssueStatusFor(final String issueId, final TestResult testResult) {
LOGGER.info("Updating status for issue {} with test result {}", issueId, testResult);
String currentStatus = issueTracker.getStatusFor(issueId);
LOGGER.info("Issue {} currently has status '{}'", issueId, currentStatus);
List transitions = getWorkflow().getTransitions().forTestResult(testResult).whenIssueIs(currentStatus);
LOGGER.info("Found transitions {} for issue {}", transitions, issueId);
for (String transition : transitions) {
issueTracker.doTransition(issueId, transition);
}
}
private List namedTestResultsFrom(List testOutcomes) {
return testOutcomes.stream().map(testOutcome -> new NamedTestResult(testOutcome.getTitle(),testOutcome.getTestResult())).collect(Collectors.toList());
}
private TestResultComment newOrUpdatedCommentFor(final String issueId, List testOutcomes) {
LOGGER.info("Updating comments for issue {}", issueId);
LOGGER.info("WIKI Rendering activated: {}", isWikiRenderedActive());
List comments = issueTracker.getCommentsFor(issueId);
Optional existingComment = findExistingSerenityCommentIn(comments);
String testRunNumber = environmentVariables.getProperty(BUILD_ID_PROPERTY);
TestResultComment testResultComment;
List newTestResults = namedTestResultsFrom(testOutcomes);
if (!existingComment.isPresent() || createNewCommentForEachUpdate()) {
testResultComment = TestResultComment.comment(isWikiRenderedActive())
.withResults(namedTestResultsFrom(testOutcomes))
.withReportUrl(linkToReport(testOutcomes))
.forTestsExecutedAt(LocalDateTime.now())
.withTestRun(testRunNumber).asComment();
if (!dryRun()) {
issueTracker.addComment(issueId, testResultComment.asText());
}
} else {
testResultComment = TestResultComment.fromText(existingComment.get().getBody())
.withWikiRendering(isWikiRenderedActive())
.withUpdatedTestResults(newTestResults)
.withUpdatedReportUrl(linkToReport(testOutcomes))
.forTestsExecutedAt(LocalDateTime.now())
.withUpdatedTestRunNumber(testRunNumber);
IssueComment updatedComment = existingComment.get().withText(testResultComment.asText());
if (!dryRun()) {
issueTracker.updateComment(issueId, updatedComment);
}
}
return testResultComment;
}
private boolean createNewCommentForEachUpdate() {
return environmentVariables.getPropertyAsBoolean(ALWAYS_CREATE_NEW_COMMENT, false);
}
private Optional findExistingSerenityCommentIn(List comments) {
return comments.stream()
.filter(comment -> comment.getBody().contains(SERENITY_COMMENT_HEADING))
.findFirst();
}
private void logIssueTracking(final String issueId) {
if (dryRun()) {
LOGGER.info("--- DRY RUN ONLY: JIRA WILL NOT BE UPDATED ---");
}
LOGGER.info("Updating JIRA issue: " + issueId);
LOGGER.info("JIRA server: " + issueTracker.toString());
}
private boolean dryRun() {
return Boolean.parseBoolean(environmentVariables.getProperty(SKIP_JIRA_UPDATES));
}
private String linkToReport(List testOutcomes) {
TestOutcomeSummary firstTestOutcome = testOutcomes.get(0);
String reportUrl = ThucydidesSystemProperty.SERENITY_PUBLIC_URL.from(environmentVariables, "");
String reportName = firstTestOutcome.getReportName() + ".html";
return formatTestResultsLink(reportUrl, reportName);
}
private String formatTestResultsLink(String reportUrl, String reportName) {
return reportUrl + "/" + reportName;
}
private boolean isWikiRenderedActive() {
return configuration.isWikiRenderedActive();
}
public List getPrefixedIssuesWithoutHashes(TestOutcomeSummary result) {
return addPrefixesIfRequired(stripInitialHashesFrom(issueReferencesIn(result)));
}
private List addPrefixesIfRequired(final List issueNumbers) {
return issueNumbers.stream().map(this::toIssueNumbersWithPrefixes).collect(Collectors.toList());
}
private List issueReferencesIn(TestOutcomeSummary result) {
return result.getIssues();
}
private String toIssueNumbersWithPrefixes(String issueNumber) {
if (StringUtils.isEmpty(projectPrefix)) {
return issueNumber;
}
if (issueNumber.startsWith(projectPrefix)) {
return issueNumber;
}
return projectPrefix + "-" + issueNumber;
}
private List stripInitialHashesFrom(final List issueNumbers) {
return issueNumbers.stream().map(this::toIssueNumbersWithoutHashes).collect(Collectors.toList());
}
@Override
public int hashCode() {
return super.hashCode();
}
private String toIssueNumbersWithoutHashes(String issueNumber) {
if (issueNumber.startsWith("#")) {
return issueNumber.substring(1);
} else {
return issueNumber;
}
}
private int getMaxJobs() {
return environmentVariables.getPropertyAsInteger("jira.max.threads", DEFAULT_MAX_THREADS);
}
protected Workflow getWorkflow() {
return workflow;
}
protected boolean shouldUpdateWorkflow() {
return Boolean.valueOf(environmentVariables.getProperty(ClasspathWorkflowLoader.ACTIVATE_WORKFLOW_PROPERTY));
}
public IssueTracker getIssueTracker() {
return issueTracker;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy