Skip to content

Commit

Permalink
TS-8032 Walk submodules in root project
Browse files Browse the repository at this point in the history
- TODO: Only execute in root project
- TODO: Recursively walk submodules of submodules
  • Loading branch information
AlEscher committed Apr 28, 2023
1 parent 3a502bf commit d244a82
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -124,8 +125,8 @@ protected Xpp3Dom getConfigurationDom(String pluginArtifact) {
* @param pluginGoal The name of the goal
* @return The configuration DOM if present, otherwise <code>null</code>
*/
protected Xpp3Dom getExecutionConfigurationDom(String pluginArtifact, String pluginGoal) {
Plugin plugin = session.getCurrentProject().getPlugin(pluginArtifact);
protected Xpp3Dom getExecutionConfigurationDom(MavenProject project, String pluginArtifact, String pluginGoal) {
Plugin plugin = project.getPlugin(pluginArtifact);
if (plugin == null) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import shadow.com.teamscale.client.CommitDescriptor;
import shadow.com.teamscale.client.EReportFormat;
import shadow.com.teamscale.client.TeamscaleClient;

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.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
* Binds to the VERIFY phase in which the Jacoco plugin generates its report.
Expand All @@ -36,28 +38,22 @@ public class CoverageUploadMojo extends TeamscaleMojoBase {
private final static String JACOCO_PLUGIN_NAME = "org.jacoco:jacoco-maven-plugin";

/**
* The directory where Jacoco creates directories for its report by default, usually "./target/site"
*/
@Parameter(defaultValue = "${project.reporting.outputDirectory}")
private String reportDirectory;

/**
* The directory in which Jacoco will place its reports
* Paths to all reports generated by subprojects
* @see <a href="https://www.jacoco.org/jacoco/trunk/doc/report-mojo.html">report</a>
*/
private Path reportGoalOutputDirectory;
private final List<Path> reportGoalOutputFiles = new ArrayList<>();

/**
* The directory in which Jacoco will place its reports for the report-integration goal
* Paths to all integration reports generated by subprojects
* @see <a href="https://www.jacoco.org/jacoco/trunk/doc/report-integration-mojo.html">report-integration</a>
*/
private Path reportIntegrationGoalOutputDirectory;
private final List<Path> reportIntegrationGoalOutputFiles = new ArrayList<>();

/**
* The directory in which Jacoco will place its reports for the report-aggregate goal
* Paths to all aggregated reports generated by subprojects
* @see <a href="https://www.jacoco.org/jacoco/trunk/doc/report-aggregate-mojo.html">report-aggregate</a>
*/
private Path reportAggregateGoalOutputDirectory;
private final List<Path> reportAggregateGoalOutputFiles = new ArrayList<>();

/**
* The Teamscale client that is used to upload reports to a Teamscale instance.
Expand Down Expand Up @@ -87,46 +83,50 @@ public void execute() throws MojoFailureException {
* @throws MojoFailureException If Jacoco is not set up correctly
*/
private void parseJacocoConfiguration() throws MojoFailureException {
// If a Dom is null it means the execution goal uses default parameters which work correctly
Xpp3Dom reportConfigurationDom = getJacocoGoalExecutionConfiguration("report");
validateReportFormat(reportConfigurationDom, "report");
reportGoalOutputDirectory = getCustomOutputDirectory(reportConfigurationDom).orElse(Paths.get(reportDirectory).resolve("jacoco"));

Xpp3Dom reportIntegrationConfigurationDom = getJacocoGoalExecutionConfiguration("report-integration");
validateReportFormat(reportIntegrationConfigurationDom, "report-integration");
reportIntegrationGoalOutputDirectory = getCustomOutputDirectory(reportIntegrationConfigurationDom).orElse(Paths.get(reportDirectory).resolve("jacoco-it"));

Xpp3Dom reportAggregateConfigurationDom = getJacocoGoalExecutionConfiguration("report-aggregate");
validateReportFormat(reportAggregateConfigurationDom, "report-aggregate");
reportAggregateGoalOutputDirectory = getCustomOutputDirectory(reportAggregateConfigurationDom).orElse(Paths.get(reportDirectory).resolve("jacoco-aggregate"));
for (MavenProject subProject : session.getTopLevelProject().getCollectedProjects()) {
Path defaultOutputDirectory = Paths.get(subProject.getReporting().getOutputDirectory());
// If a Dom is null it means the execution goal uses default parameters which work correctly
Xpp3Dom reportConfigurationDom = getJacocoGoalExecutionConfiguration(subProject,"report");
if (!validateReportFormat(reportConfigurationDom)) {
throw new MojoFailureException(String.format("%s in %s is not configured to produce XML reports for goal %s", JACOCO_PLUGIN_NAME, subProject.getName(), "report"));
}
reportGoalOutputFiles.add(getCustomOutputDirectory(reportConfigurationDom).orElse(defaultOutputDirectory.resolve("jacoco").resolve("jacoco.xml")));

Xpp3Dom reportIntegrationConfigurationDom = getJacocoGoalExecutionConfiguration(subProject,"report-integration");
if (!validateReportFormat(reportIntegrationConfigurationDom)) {
throw new MojoFailureException(String.format("%s in %s is not configured to produce XML reports for goal %s", JACOCO_PLUGIN_NAME, subProject.getName(), "report-integration"));
}
reportIntegrationGoalOutputFiles.add(getCustomOutputDirectory(reportConfigurationDom).orElse(defaultOutputDirectory.resolve("jacoco-it").resolve("jacoco.xml")));

Xpp3Dom reportAggregateConfigurationDom = getJacocoGoalExecutionConfiguration(subProject,"report-aggregate");
if (!validateReportFormat(reportAggregateConfigurationDom)) {
throw new MojoFailureException(String.format("%s in %s is not configured to produce XML reports for goal %s", JACOCO_PLUGIN_NAME, subProject.getName(), "report-aggregate"));
}
reportAggregateGoalOutputFiles.add(getCustomOutputDirectory(reportConfigurationDom).orElse(defaultOutputDirectory.resolve("jacoco-aggregate").resolve("jacoco.xml")));
}
}

private void uploadCoverageReports() throws IOException {
uploadCoverage(reportGoalOutputDirectory, "Unit Tests");
uploadCoverage(reportIntegrationGoalOutputDirectory, "Integration Tests");
uploadCoverage(reportAggregateGoalOutputDirectory, "Aggregated Reports");
uploadCoverage(reportGoalOutputFiles, "Unit Tests");
uploadCoverage(reportIntegrationGoalOutputFiles, "Integration Tests");
uploadCoverage(reportAggregateGoalOutputFiles, "Aggregated Reports");
}

private void uploadCoverage(Path reportOutputDirectory, String partition) throws IOException {
File jacocoReport = reportOutputDirectory.resolve("jacoco.xml").toFile();
if (!jacocoReport.exists() || !jacocoReport.canRead()) {
getLog().debug(String.format("%s does not exist or is not accessible", jacocoReport.toPath()));
return;
private void uploadCoverage(List<Path> reportOutputFiles, String partition) throws IOException {
Collection<File> reports = reportOutputFiles.stream().map(Path::toFile).filter(File::canRead).collect(Collectors.toList());
if (!reports.isEmpty()) {
getLog().debug(String.format("Uploading Jacoco report for project %s to %s", projectId, partition));
teamscaleClient.uploadReports(EReportFormat.JACOCO, reports, CommitDescriptor.parse(resolvedEndCommit), revision, partition, "External upload via Teamscale Maven plugin");
}
String report = new String(Files.readAllBytes(jacocoReport.toPath()));
getLog().debug(String.format("Uploading Jacoco report for project %s to %s", projectId, partition));
teamscaleClient.uploadReport(EReportFormat.JACOCO, report, CommitDescriptor.parse(resolvedEndCommit), revision, partition, "External upload via Teamscale Maven plugin");
}

/**
* Validates that a configuration Dom is set up to generate XML reports
* @param configurationDom The configuration Dom of a goal execution
* @param pluginGoal The name of the goal
* @throws MojoFailureException If the goal is not set up to generate XML reports
*/
private void validateReportFormat(Xpp3Dom configurationDom, String pluginGoal) throws MojoFailureException {
private boolean validateReportFormat(Xpp3Dom configurationDom) {
if (configurationDom == null || configurationDom.getChild("formats") == null) {
return;
return true;
}
boolean producesXMLReport = false;
for (Xpp3Dom format : configurationDom.getChild("formats").getChildren()) {
Expand All @@ -135,9 +135,7 @@ private void validateReportFormat(Xpp3Dom configurationDom, String pluginGoal) t
break;
}
}
if (!producesXMLReport) {
throw new MojoFailureException(JACOCO_PLUGIN_NAME + " is not configured to produce XML reports for goal " + pluginGoal);
}
return producesXMLReport;
}

private Optional<Path> getCustomOutputDirectory(Xpp3Dom configurationDom) {
Expand All @@ -147,7 +145,7 @@ private Optional<Path> getCustomOutputDirectory(Xpp3Dom configurationDom) {
return Optional.empty();
}

private Xpp3Dom getJacocoGoalExecutionConfiguration(String pluginGoal) {
return super.getExecutionConfigurationDom(JACOCO_PLUGIN_NAME, pluginGoal);
private Xpp3Dom getJacocoGoalExecutionConfiguration(MavenProject project, String pluginGoal) {
return super.getExecutionConfigurationDom(project, JACOCO_PLUGIN_NAME, pluginGoal);
}
}

0 comments on commit d244a82

Please sign in to comment.