package io.qameta.allure.bamboo;
import com.atlassian.bamboo.build.logger.BuildLogger;
import com.atlassian.bamboo.process.EnvironmentVariableAccessor;
import com.atlassian.bamboo.process.ExternalProcessBuilder;
import com.atlassian.bamboo.process.ProcessService;
import com.atlassian.bamboo.task.*;
import com.atlassian.bamboo.v2.build.agent.capability.CapabilityContext;
import com.atlassian.bamboo.variable.CustomVariableContext;
import com.atlassian.bamboo.variable.VariableDefinitionContext;
import com.atlassian.core.util.FileUtils;
import com.atlassian.utils.process.ExternalProcess;
import com.google.common.base.Preconditions;
import io.qameta.allure.bamboo.info.AddExecutorInfo;
import io.qameta.allure.bamboo.info.AddTestRunInfo;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import static io.qameta.allure.bamboo.AllureConstants.*;
/**
* Executes report generation.
* Created by bvo2002 on 30.11.16.
*/
public class AllureReportTask implements TaskType {
private final ProcessService processService;
private final EnvironmentVariableAccessor environmentVariableAccessor;
private final CapabilityContext capabilityContext;
private final AllureCapability helper;
private CustomVariableContext customVariableContext;
@Autowired
public AllureReportTask(ProcessService processService,
EnvironmentVariableAccessor environmentVariableAccessor,
CapabilityContext capabilityContext, CustomVariableContext customVariableContext) {
this.processService = processService;
this.environmentVariableAccessor = environmentVariableAccessor;
this.capabilityContext = capabilityContext;
this.helper = new AllureCapability();
this.customVariableContext = customVariableContext;
}
@NotNull
@Override
public TaskResult execute(@NotNull TaskContext taskContext) throws TaskException {
BuildLogger buildLogger = taskContext.getBuildLogger();
TaskResultBuilder taskResultBuilder = TaskResultBuilder.newBuilder(taskContext);
Map<String, String> environment = this.environmentVariableAccessor
.splitEnvironmentAssignments(taskContext.getConfigurationMap().get("environmentVariables"), false);
final File workingDirectory = taskContext.getWorkingDirectory();
buildLogger.addBuildLogHeader("Allure Report", true);
buildLogger.addBuildLogEntry("Trying to generate Allure using " + workingDirectory.getAbsolutePath() + " as base directory with pattern = " + taskContext.getConfigurationMap().get(RESULTS_DIRECTORY));
buildLogger.addBuildLogEntry("Allure data will be saved to " + workingDirectory.getAbsolutePath() + File.separator + taskContext.getConfigurationMap().get(REPORT_PATH_PREFIX));
try {
prepareResults(taskContext);
ExternalProcessBuilder e = new ExternalProcessBuilder();
e.workingDirectory(taskContext.getWorkingDirectory());
e.env(environment);
e.command(this.getCommandList(taskContext));
ExternalProcess externalProcess = this.processService.executeExternalProcess(taskContext, e);
taskResultBuilder.checkReturnCode(externalProcess);
} catch (Exception e) {
buildLogger.addErrorLogEntry("Caught an exception while generating Allure", e);
return TaskResultBuilder.newBuilder(taskContext).failedWithError().build();
}
buildLogger.addBuildLogEntry("Successfully generated Allure report");
return TaskResultBuilder.newBuilder(taskContext).success().build();
}
private void prepareResults(TaskContext taskContext) throws IOException, InterruptedException {
copyHistory(taskContext);
clearReport(taskContext);
addTestRunInfo(taskContext);
addExecutorInfo(taskContext);
}
private void copyHistory(TaskContext taskContext) throws IOException {
Path source = Paths.get(getReportDirectory(taskContext).getAbsolutePath()).resolve("history");
if (Files.exists(source)) {
Path destination = Paths.get(getResultDirectory(taskContext).getAbsolutePath()).resolve("history");
FileUtils.copyDirectory(source.toFile(), destination.toFile(), true);
}
}
private void clearReport(TaskContext taskContext) throws IOException {
Path reportDirectory = Paths.get(getReportDirectory(taskContext).getAbsolutePath());
if (Files.exists(reportDirectory)) {
FileUtils.recursiveDelete(reportDirectory.toFile());
}
}
private void addTestRunInfo(TaskContext taskContext) throws IOException, InterruptedException {
long start = taskContext.getBuildContext().getBuildResult().getTasksStartDate().getTime();
long stop = new Date().getTime();
String buildName = taskContext.getBuildContext().getDisplayName();
new AddTestRunInfo(buildName, start, stop).invoke(getResultDirectory(taskContext));
}
private void addExecutorInfo(TaskContext taskContext) throws IOException, InterruptedException {
Map<String, VariableDefinitionContext> buildVariables = customVariableContext.getVariableContexts();
String buildResultsUrl = buildVariables.get("buildResultsUrl").getValue();
String rootUrl = buildResultsUrl.substring(0, buildResultsUrl.indexOf("bamboo") + "bamboo".length());
String buildUrl = rootUrl + "/browse/" + buildVariables.get("planKey").getValue() + "-" + taskContext.getBuildContext().getBuildNumber();
String buildName = taskContext.getBuildContext().getDisplayName();
String reportUrl = buildUrl + "/artifact/" + buildVariables.get("shortJobKey").getValue() + "/" + ARTIFACT_NAME.replace(" ", "-") + "/index.html";
new AddExecutorInfo(rootUrl, buildName, buildUrl, reportUrl).invoke(getResultDirectory(taskContext));
}
@NotNull
private File getResultDirectory(TaskContext taskContext) {
return new File(taskContext.getWorkingDirectory().getAbsolutePath()
+ File.separator + taskContext.getConfigurationMap().get(RESULTS_DIRECTORY));
}
@NotNull
private File getReportDirectory(TaskContext taskContext) {
return new File(taskContext.getWorkingDirectory().getAbsolutePath()
+ File.separator + taskContext.getConfigurationMap().get(REPORT_PATH_PREFIX));
}
private List<String> getCommandList(TaskContext taskContext) throws TaskException {
List<String> list = new ArrayList<>();
list.add(this.getExecutable(taskContext));
list.add("generate");
list.add(taskContext.getConfigurationMap().get(RESULTS_DIRECTORY));
list.add("-o");
list.add(taskContext.getConfigurationMap().get(REPORT_PATH_PREFIX));
return list;
}
private String getExecutable(TaskContext taskContext) {
BuildLogger buildLogger = taskContext.getBuildLogger();
String path = this.getCapabilityPath(taskContext);
String executableName = this.helper.getExecutableName();
String executableFile = path + File.separatorChar + "bin" + File.separatorChar + executableName;
File file = new File(executableFile);
if (!file.isAbsolute())
file = new File(taskContext.getWorkingDirectory(), executableFile);
buildLogger.addBuildLogEntry("Allure executable file: " + executableFile);
if (!file.exists())
throw new IllegalStateException("Cannot find executable \'" + executableFile + "\'");
return file.getAbsolutePath();
}
@NotNull
private String getCapabilityPath(CommonTaskContext taskContext) {
String builderLabel = Preconditions.checkNotNull(taskContext.getConfigurationMap().get(EXECUTABLE_LABEL),
"Executable label is not defined");
return Preconditions.checkNotNull(this.capabilityContext.getCapabilityValue(AllureCapability.ALLURE_CAPABILITY_PREFIX + "." + builderLabel),
"Executable path is not defined");
}
}