Skip to content

Commit

Permalink
introduce single file report mode (fixes #755, via #2072)
Browse files Browse the repository at this point in the history
  • Loading branch information
baev authored Aug 24, 2023
1 parent cb08a70 commit 8d41e9d
Show file tree
Hide file tree
Showing 93 changed files with 1,507 additions and 419 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ public ExitCode run() {
generateCommand.getReportDirectory(),
generateCommand.getResultsOptions().getResultsDirectories(),
generateCommand.isCleanReportDirectory(),
generateCommand.isSingleFileMode(),
generateCommand.getConfigOptions()
);
case SERVE_COMMAND:
Expand Down
25 changes: 16 additions & 9 deletions allure-commandline/src/main/java/io/qameta/allure/Commands.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public class Commands {

private static final Logger LOGGER = LoggerFactory.getLogger(Commands.class);
private static final String DIRECTORY_EXISTS_MESSAGE = "Allure: Target directory {} for the report is already"
+ " in use, add a '--clean' option to overwrite";
+ " in use, add a '--clean' option to overwrite";

private final Path allureHome;

Expand Down Expand Up @@ -91,19 +91,26 @@ public ExitCode generate(final Path reportDirectory,
final List<Path> resultsDirectories,
final boolean clean,
final ConfigOptions profile) {
return generate(reportDirectory, resultsDirectories, clean, false, profile);
}

public ExitCode generate(final Path reportDirectory,
final List<Path> resultsDirectories,
final boolean clean,
final boolean singleFileMode,
final ConfigOptions profile) {
final boolean directoryExists = Files.exists(reportDirectory);
if (clean && directoryExists) {
FileUtils.deleteQuietly(reportDirectory.toFile());
} else if (directoryExists && isDirectoryNotEmpty(reportDirectory)) {
LOGGER.error(DIRECTORY_EXISTS_MESSAGE, reportDirectory.toAbsolutePath());
return ExitCode.GENERIC_ERROR;
}
try {
final ReportGenerator generator = new ReportGenerator(createReportConfiguration(profile));
final ReportGenerator generator = new ReportGenerator(createReportConfiguration(profile));
if (singleFileMode) {
generator.generateSingleFile(reportDirectory, resultsDirectories);
} else {
generator.generate(reportDirectory, resultsDirectories);
} catch (IOException e) {
LOGGER.error("Could not generate report", e);
return ExitCode.GENERIC_ERROR;
}
LOGGER.info("Report successfully generated to {}", reportDirectory);
return ExitCode.NO_ERROR;
Expand Down Expand Up @@ -152,7 +159,7 @@ public ExitCode open(final Path reportDirectory, final String host, final int po
openBrowser(server.getURI());
} catch (IOException | AWTError e) {
LOGGER.error(
"Could not open the report in browser, try to open it manually {}: {}",
"Could not open the report in browser, try to open it manually {}",
server.getURI(),
e
);
Expand Down Expand Up @@ -221,11 +228,11 @@ protected void openBrowser(final URI url) throws IOException {
Desktop.getDesktop().browse(url);
} catch (UnsupportedOperationException e) {
LOGGER.error("Browse operation is not supported on your platform."
+ "You can use the link below to open the report manually.", e);
+ "You can use the link below to open the report manually.", e);
}
} else {
LOGGER.error("Can not open browser because this capability is not supported on "
+ "your platform. You can use the link below to open the report manually.");
+ "your platform. You can use the link below to open the report manually.");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ public class GenerateCommand {
)
private Path reportDirectory = Paths.get("allure-report");

@Parameter(
names = {"--single-file"},
description = "Generate Allure report in single file mode."
)
private boolean singleFileMode;

@ParametersDelegate
private ResultsOptions resultsOptions = new ResultsOptions();

Expand All @@ -68,4 +74,8 @@ public ResultsOptions getResultsOptions() {
public ConfigOptions getConfigOptions() {
return configOptions;
}

public boolean isSingleFileMode() {
return singleFileMode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

Expand Down Expand Up @@ -57,6 +58,7 @@ void shouldLoadEmptyPlugin(@TempDir final Path pluginDirectory) {
.isEmpty();
}

@SuppressWarnings("deprecation")
@Test
void shouldLoadPluginExtensions(@TempDir final Path pluginFolder) throws Exception {
add(pluginFolder, "plugin.jar", "plugin.jar");
Expand Down Expand Up @@ -108,14 +110,16 @@ void shouldLoadStaticOnlyPlugin(@TempDir final Path temp) throws Exception {
.isNotNull()
.isEmpty();

final Path unpack = Files.createDirectories(temp.resolve("unpack"));
plugin.unpackReportStatic(unpack);

assertThat(unpack.resolve("some-file"))
final Map<String, Path> pluginFiles = plugin.getPluginFiles();

assertThat(pluginFiles).containsKey("some-file");
assertThat(pluginFiles.get("some-file"))
.isRegularFile()
.hasContent("ho-ho-ho");
}

@SuppressWarnings("deprecation")
@Test
void shouldLoadJarsInLibDirectory(@TempDir final Path pluginFolder) throws Exception {
add(pluginFolder, "plugin.jar", "lib/plugin.jar");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import io.qameta.allure.core.Configuration;
import io.qameta.allure.core.MarkdownDescriptionsPlugin;
import io.qameta.allure.core.Plugin;
import io.qameta.allure.core.ReportWebPlugin;
import io.qameta.allure.core.TestsResultsPlugin;
import io.qameta.allure.duration.DurationPlugin;
import io.qameta.allure.duration.DurationTrendPlugin;
Expand Down Expand Up @@ -110,7 +109,6 @@ public ConfigurationBuilder useDefault() {
new StatusChartPlugin(),
new TimelinePlugin(),
new SuitesPlugin(),
new ReportWebPlugin(),
new TestsResultsPlugin(),
new AttachmentsPlugin(),
new MailPlugin(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
* Default implementation of {@link Configuration}.
Expand All @@ -46,26 +45,13 @@ public List<Plugin> getPlugins() {
}

@Override
public List<Aggregator> getAggregators() {
return extensions.stream()
.filter(Aggregator.class::isInstance)
.map(Aggregator.class::cast)
.collect(Collectors.toList());
public List<Extension> getExtensions() {
return Collections.unmodifiableList(extensions);
}

@Override
public List<Reader> getReaders() {
return extensions.stream()
.filter(Reader.class::isInstance)
.map(Reader.class::cast)
.collect(Collectors.toList());
}

@Override
public <T> Optional<T> getContext(final Class<T> contextType) {
return extensions.stream()
.filter(contextType::isInstance)
.map(contextType::cast)
public <S, T extends Context<S>> Optional<T> getContext(final Class<T> contextType) {
return getExtensions(contextType).stream()
.findFirst();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ private static String getExtensionByMimeType(final String type) {
try {
return getDefaultMimeTypes().forName(type).getExtension();
} catch (Exception e) {
LOGGER.warn("Can't detect extension for MIME-type {} {}", type, e);
LOGGER.warn("Can't detect extension for MIME-type {}", type, e);
return "";
}
}
Expand All @@ -129,7 +129,7 @@ public static String probeContentType(final Path path) {
try (InputStream stream = newInputStream(path)) {
return probeContentType(stream, Objects.toString(path.getFileName()));
} catch (IOException e) {
LOGGER.warn("Couldn't detect the media type of attachment {} {}", path, e);
LOGGER.warn("Couldn't detect the media type of attachment {}", path, e);
return WILDCARD;
}
}
Expand All @@ -140,7 +140,7 @@ public static String probeContentType(final InputStream is, final String name) {
metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, name);
return getDefaultMimeTypes().detect(stream, metadata).toString();
} catch (IOException e) {
LOGGER.warn("Couldn't detect the media type of attachment {} {}", name, e);
LOGGER.warn("Couldn't detect the media type of attachment {}", name, e);
return WILDCARD;
}
}
Expand All @@ -149,7 +149,7 @@ private static Long getFileSizeSafe(final Path path) {
try {
return size(path);
} catch (IOException e) {
LOGGER.warn("Could not get the size of file {} {}", path, e);
LOGGER.warn("Could not get the size of file {}", path, e);
return null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@
import io.qameta.allure.context.ReportInfoContext;
import io.qameta.allure.core.AttachmentsPlugin;
import io.qameta.allure.core.Configuration;
import io.qameta.allure.core.LaunchResults;
import io.qameta.allure.core.MarkdownDescriptionsPlugin;
import io.qameta.allure.core.Plugin;
import io.qameta.allure.core.ReportWebPlugin;
import io.qameta.allure.core.TestsResultsPlugin;
import io.qameta.allure.duration.DurationPlugin;
import io.qameta.allure.duration.DurationTrendPlugin;
Expand Down Expand Up @@ -80,9 +78,9 @@ public final class DummyReportGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(DummyReportGenerator.class);
private static final int MIN_ARGUMENTS_COUNT = 2;
private static final List<Extension> EXTENSIONS = Arrays.asList(
new ReportInfoContext("dev"),
new JacksonContext(),
new MarkdownContext(),
new ReportInfoContext("dev"),
new FreemarkerContext(),
new RandomUidContext(),
new MarkdownDescriptionsPlugin(),
Expand Down Expand Up @@ -111,16 +109,7 @@ public final class DummyReportGenerator {
new LaunchPlugin(),
new Allure1Plugin(),
new Allure1EnvironmentPlugin(),
new Allure2Plugin(),
new ReportWebPlugin() {
@Override
public void aggregate(final Configuration configuration,
final List<LaunchResults> launchesResults,
final Path outputDirectory) throws IOException {
writePluginsStatic(configuration, outputDirectory);
writeIndexHtml(configuration, outputDirectory);
}
}
new Allure2Plugin()
);

private DummyReportGenerator() {
Expand Down Expand Up @@ -148,7 +137,7 @@ public static void main(final String... args) throws IOException {
.fromPlugins(plugins)
.build();
final ReportGenerator generator = new ReportGenerator(configuration);
generator.generate(files[lastIndex], Arrays.copyOf(files, lastIndex));
generator.generateSingleFile(files[lastIndex], Arrays.asList(Arrays.copyOf(files, lastIndex)));
}

public static Path[] getFiles(final String... paths) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,25 @@
package io.qameta.allure;

import io.qameta.allure.core.Configuration;
import io.qameta.allure.core.FileSystemReportStorage;
import io.qameta.allure.core.InMemoryReportStorage;
import io.qameta.allure.core.LaunchResults;
import io.qameta.allure.core.ReportWebGenerator;
import io.qameta.allure.util.DeleteVisitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* @author charlie (Dmitry Baev).
Expand All @@ -40,34 +49,82 @@ public ReportGenerator(final Configuration configuration) {
this.configuration = configuration;
}

public LaunchResults readResults(final Path resultsDirectory) {
private LaunchResults readResults(final Path resultsDirectory) {
final DefaultResultsVisitor visitor = new DefaultResultsVisitor(configuration);
configuration
.getReaders()
configuration.getExtensions(Reader.class)
.forEach(reader -> reader.readResults(configuration, visitor, resultsDirectory));
return visitor.getLaunchResults();
}

public void aggregate(final List<LaunchResults> results, final Path outputDirectory) throws IOException {
for (Aggregator aggregator : configuration.getAggregators()) {
aggregator.aggregate(configuration, results, outputDirectory);
private void aggregate(final List<LaunchResults> results, final ReportStorage storage) {
processOldAggregators(results, storage);

for (final Aggregator2 aggregator : configuration.getExtensions(Aggregator2.class)) {
aggregator.aggregate(configuration, results, storage);
}
}

public void generate(final Path outputDirectory, final List<Path> resultsDirectories) throws IOException {
generate(outputDirectory, resultsDirectories.stream());
@SuppressWarnings("deprecation")
private void processOldAggregators(final List<LaunchResults> results,
final ReportStorage storage) {
Path tempDir = null;
try {
tempDir = Files.createTempDirectory("allure-");

for (Aggregator aggregator : configuration.getExtensions(Aggregator.class)) {
aggregator.aggregate(configuration, results, tempDir);
}

final Path finalTempDir = tempDir;
Files.walkFileTree(tempDir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(final Path file,
final BasicFileAttributes attrs) {
final String fileId = file.relativize(finalTempDir).toString();
storage.addDataFile(fileId, file);
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
throw new UncheckedIOException(e);
} finally {
if (Objects.nonNull(tempDir)) {
try {
Files.walkFileTree(tempDir, new DeleteVisitor());
} catch (IOException ignored) {
// do nothing
}
}
}

}

public void generate(final Path outputDirectory, final Path... resultsDirectories) throws IOException {
generate(outputDirectory, Stream.of(resultsDirectories));
public void generate(final Path outputDirectory, final List<Path> resultsDirectories) {
generate(
new FileSystemReportStorage(outputDirectory),
outputDirectory,
resultsDirectories
);
}

private void generate(final Path outputDirectory, final Stream<Path> resultsDirectories) throws IOException {
final List<LaunchResults> results = resultsDirectories
public void generate(final Path outputDirectory, final Path... resultsDirectories) {
generate(outputDirectory, Arrays.asList(resultsDirectories));
}

private void generate(final ReportStorage storage,
final Path outputDirectory,
final List<Path> resultsDirectories) {
final List<LaunchResults> results = resultsDirectories.stream()
.filter(this::isValidResultsDirectory)
.map(this::readResults)
.collect(Collectors.toList());
aggregate(results, outputDirectory);
aggregate(results, storage);
new ReportWebGenerator().generate(configuration, storage, outputDirectory);
}

public void generateSingleFile(final Path outputDirectory, final List<Path> resultsDirectories) {
final InMemoryReportStorage storage = new InMemoryReportStorage();
generate(storage, outputDirectory, resultsDirectories);
}

private boolean isValidResultsDirectory(final Path resultsDirectory) {
Expand Down
Loading

0 comments on commit 8d41e9d

Please sign in to comment.