Compare commits

..

No commits in common. "9e6471c74b72359f1efa3472b1a8f2a25ba22434" and "3f7018096ef247bbae02dde4ee7a42af8a47a9f5" have entirely different histories.

10 changed files with 39749 additions and 152 deletions

View file

@ -1,32 +0,0 @@
name: bld-ci
on: [ push, pull_request, workflow_dispatch ]
jobs:
build-bld-project:
runs-on: ubuntu-latest
strategy:
matrix:
java-version: [ 17, 20 ]
steps:
- name: Checkout source repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up JDK ${{ matrix.java-version }}
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: ${{ matrix.java-version }}
- name: Grant execute permission for bld
run: chmod +x bld
- name: Download the dependencies
run: ./bld download
- name: Run tests with bld
run: ./bld compile test

View file

@ -1,57 +0,0 @@
name: javadocs-pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["master"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow one concurrent deployment
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
# Single deploy job since we're just deploying
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout source repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 17
- name: Build Javadocs
run: ./bld download clean javadoc
- name: Setup Pages
uses: actions/configure-pages@v3
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
with:
# Upload generated Javadocs repository
path: 'build/javadoc/'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1

1
.idea/misc.xml generated
View file

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="EntryPointsManager"> <component name="EntryPointsManager">
<entry_points version="2.0"> <entry_points version="2.0">

View file

@ -1,28 +0,0 @@
# [Bld](https://rife2.com/bld) Extension to Code Coverage Analysis with [JaCoCo](https://www.eclemma.org/jacoco/)
[![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](http://opensource.org/licenses/BSD-3-Clause)
[![Java](https://img.shields.io/badge/java-17%2B-blue)](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
[![Release](https://flat.badgen.net/maven/v/metadata-url/repo.rife2.com/releases/com/uwyn/rife2/bld-jacoco-report/maven-metadata.xml?color=blue)](https://repo.rife2.com/#/releases/com/uwyn/rife2/bld-jacoco-report)
[![Snapshot](https://flat.badgen.net/maven/v/metadata-url/repo.rife2.com/snapshots/com/uwyn/rife2/bld-jacoco-report/maven-metadata.xml?label=snapshot)](https://repo.rife2.com/#/snapshots/com/uwyn/rife2/bld-jacoco-report)
[![GitHub CI](https://github.com/rife2/bld-jacoco-report/actions/workflows/bld.yml/badge.svg)](https://github.com/rife2/bld-jacoco-report/actions/workflows/bld.yml)
To run the tests and generate the code coverage reports:
```java
@BuildCommand(summary = "Generates Jacoco Reports")
public void jacoco() throws IOException {
new JacocoReportOperation()
.fromProject(this)
.execute();
}
```
```text
./bld compile jacoco
```
- The HTML, CVS and XML reports will be automatically created in the `build/reports/jacoco/test` directory.
- The execution coverage data will be automatically recorded in the `build/jacoco/jacoco.exec` file.
Please check the [JacocoReportOperation documentation](https://rife2.github.io/bld-jacoco-report/rife/bld/extension/JacocoOperation.html#method-summary) for all available configuration options.

View file

@ -27,11 +27,12 @@ public class ExamplesBuild extends Project {
new ExamplesBuild().start(args); new ExamplesBuild().start(args);
} }
// @Override
// public void test() throws Exception { @Override
// super.test(); public void test() throws Exception {
// jacoco(); super.test();
// } jacoco();
}
@BuildCommand(summary = "Generates Jacoco Reports") @BuildCommand(summary = "Generates Jacoco Reports")
public void jacoco() throws IOException { public void jacoco() throws IOException {

File diff suppressed because it is too large Load diff

16165
examples/test/index.html Normal file

File diff suppressed because it is too large Load diff

View file

@ -23,7 +23,9 @@ import rife.bld.publish.PublishDeveloper;
import rife.bld.publish.PublishLicense; import rife.bld.publish.PublishLicense;
import rife.bld.publish.PublishScm; import rife.bld.publish.PublishScm;
import java.io.File;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import static rife.bld.dependencies.Repository.*; import static rife.bld.dependencies.Repository.*;
import static rife.bld.dependencies.Scope.*; import static rife.bld.dependencies.Scope.*;
@ -49,8 +51,8 @@ public class JacocoReportOperationBuild extends Project {
scope(runtime) scope(runtime)
.include(dependency("org.jacoco", "jacoco", jacocoVersion).exclude("*", "org.jacoco.doc")); .include(dependency("org.jacoco", "jacoco", jacocoVersion).exclude("*", "org.jacoco.doc"));
scope(test) scope(test)
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 0))) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 9, 3)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 0))) .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 9, 3)))
.include(dependency("org.assertj:assertj-joda-time:2.2.0")); .include(dependency("org.assertj:assertj-joda-time:2.2.0"));
testOperation().mainClass("rife.bld.extension.JacocoReportOperationTest"); testOperation().mainClass("rife.bld.extension.JacocoReportOperationTest");
@ -61,8 +63,8 @@ public class JacocoReportOperationBuild extends Project {
.link("https://rife2.github.io/rife2/"); .link("https://rife2.github.io/rife2/");
publishOperation() publishOperation()
.repository(version.isSnapshot() ? repository("rife2-snapshot") : repository("rife2")) // .repository(version.isSnapshot() ? repository("rife2-snapshot") : repository("rife2"))
// .repository(MAVEN_LOCAL) .repository(MAVEN_LOCAL)
.info() .info()
.groupId("com.uwyn.rife2") .groupId("com.uwyn.rife2")
.artifactId("bld-jacoco-report") .artifactId("bld-jacoco-report")
@ -91,4 +93,5 @@ public class JacocoReportOperationBuild extends Project {
.ruleSets("config/pmd.xml") .ruleSets("config/pmd.xml")
.execute(); .execute();
} }
} }

View file

@ -16,22 +16,24 @@
package rife.bld.extension; package rife.bld.extension;
import org.jacoco.core.JaCoCo;
import org.jacoco.core.analysis.Analyzer; import org.jacoco.core.analysis.Analyzer;
import org.jacoco.core.analysis.CoverageBuilder; import org.jacoco.core.analysis.CoverageBuilder;
import org.jacoco.core.analysis.IBundleCoverage; import org.jacoco.core.analysis.IBundleCoverage;
import org.jacoco.core.data.ExecutionDataStore; import org.jacoco.core.data.ExecutionDataStore;
import org.jacoco.core.instr.Instrumenter;
import org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator;
import org.jacoco.core.tools.ExecFileLoader; import org.jacoco.core.tools.ExecFileLoader;
import org.jacoco.report.*; import org.jacoco.report.*;
import org.jacoco.report.csv.CSVFormatter; import org.jacoco.report.csv.CSVFormatter;
import org.jacoco.report.html.HTMLFormatter; import org.jacoco.report.html.HTMLFormatter;
import org.jacoco.report.xml.XMLFormatter; import org.jacoco.report.xml.XMLFormatter;
import rife.bld.BaseProject; import rife.bld.BaseProject;
import rife.bld.operations.AbstractOperation; import rife.bld.operations.JUnitOperation;
import rife.bld.operations.exceptions.ExitStatusException;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
@ -47,14 +49,16 @@ import java.util.logging.Logger;
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a> * @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @since 1.0 * @since 1.0
*/ */
public class JacocoReportOperation extends AbstractOperation<JacocoReportOperation> { public class JacocoReportOperation extends JUnitOperation {
private static final Logger LOGGER = Logger.getLogger(JacocoReportOperation.class.getName()); private static final Logger LOGGER = Logger.getLogger(JacocoReportOperation.class.getName());
private final List<File> classFiles = new ArrayList<>(); private final List<File> classFiles = new ArrayList<>();
private final List<File> execFiles = new ArrayList<>(); private final List<File> execFiles = new ArrayList<>();
private final List<File> instrumentedFiles = new ArrayList<>();
private final List<File> sourceFiles = new ArrayList<>(); private final List<File> sourceFiles = new ArrayList<>();
private File csv; private File csv;
private String encoding; private String encoding;
private File html; private File html;
private Instrumenter instrumenter;
private String name = "JaCoCo Coverage Report"; private String name = "JaCoCo Coverage Report";
private BaseProject project; private BaseProject project;
private boolean quiet; private boolean quiet;
@ -71,6 +75,22 @@ public class JacocoReportOperation extends AbstractOperation<JacocoReportOperati
return builder.getBundle(name); return builder.getBundle(name);
} }
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
private void buildInstrumentedFiles(File dest) throws IOException {
var total = 0;
for (var f : classFiles) {
if (f.isFile()) {
total += instrument(f, new File(dest, f.getName()));
} else {
total += instrumentRecursive(f, dest);
}
}
if (LOGGER.isLoggable(Level.INFO) && !quiet) {
LOGGER.log(Level.INFO, "{0} classes instrumented to {1}.",
new Object[]{total, dest.getAbsolutePath()});
}
}
/** /**
* Sets the locations of Java class files. * Sets the locations of Java class files.
**/ **/
@ -97,7 +117,7 @@ public class JacocoReportOperation extends AbstractOperation<JacocoReportOperati
/** /**
* Sets the locations of the JaCoCo *.exec files to read. * Sets the locations of the JaCoCo *.exec files to read.
*/ **/
public JacocoReportOperation execFiles(File... execFiles) { public JacocoReportOperation execFiles(File... execFiles) {
this.execFiles.addAll(Arrays.stream(execFiles).toList()); this.execFiles.addAll(Arrays.stream(execFiles).toList());
return this; return this;
@ -105,29 +125,21 @@ public class JacocoReportOperation extends AbstractOperation<JacocoReportOperati
/** /**
* Performs the operation execution that can be wrapped by the {@code #executeOnce} call. * Performs the operation execution that can be wrapped by the {@code #executeOnce} call.
*
* @since 1.5.10
*/ */
@Override @Override
public void execute() throws IOException { public void execute() throws IOException {
if ((project == null) && LOGGER.isLoggable(Level.SEVERE)) { if (project == null && LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.severe("A project and version must be specified."); LOGGER.severe("A project must be specified.");
} else { } else {
var buildJacocoReportsDir = Path.of(project.buildDirectory().getPath(), "reports", "jacoco", "test").toFile(); var buildJacocoReportsDir = Path.of(project.buildDirectory().getPath(), "reports", "jacoco", "test").toFile();
var buildJacocoExecDir = Path.of(project.buildDirectory().getPath(), "jacoco").toFile(); var buildJacocoExecDir = Path.of(project.buildDirectory().getPath(), "jacoco").toFile();
var buildJacocoExec = Path.of(buildJacocoExecDir.getPath(), "jacoco.exec").toFile(); var buildJacocoClassesDir = Path.of(buildJacocoExecDir.getPath(), "classes").toFile();
// project.testOperation().fromProject(project).javaOptions().javaAgent( instrumenter = new Instrumenter(new OfflineInstrumentationAccessGenerator());
// Path.of(project.libBldDirectory().getPath(), "org.jacoco.agent-" instrumenter.setRemoveSignatures(true);
// + JaCoCo.VERSION.substring(0, JaCoCo.VERSION.lastIndexOf('.')) + "-runtime.jar").toFile(),
// "destfile=" + Path.of(buildJacocoExecDir.getPath(), "jacoco.exec"));
project.testOperation().fromProject(project).javaOptions().add("-javaagent:" +
Path.of(project.libBldDirectory().getPath(), "org.jacoco.agent-"
+ JaCoCo.VERSION.substring(0, JaCoCo.VERSION.lastIndexOf('.')) + "-runtime.jar")
+ "=destfile=" + Path.of(buildJacocoExecDir.getPath(), "jacoco.exec"));
try {
project.testOperation().execute();
} catch (InterruptedException | ExitStatusException e) {
throw new IOException(e);
}
if (sourceFiles.isEmpty()) { if (sourceFiles.isEmpty()) {
sourceFiles.add(project.srcDirectory()); sourceFiles.add(project.srcDirectory());
@ -151,8 +163,15 @@ public class JacocoReportOperation extends AbstractOperation<JacocoReportOperati
csv = new File(buildJacocoReportsDir, "jacocoTestReport.csv"); csv = new File(buildJacocoReportsDir, "jacocoTestReport.csv");
} }
if (execFiles.isEmpty() && (buildJacocoExec.exists())) { if (execFiles.isEmpty()) {
execFiles.add(buildJacocoExec); //noinspection ResultOfMethodCallIgnored
buildJacocoClassesDir.mkdirs();
buildInstrumentedFiles(buildJacocoClassesDir);
var files = buildJacocoClassesDir.listFiles();
if (files != null) {
instrumentedFiles.addAll(Arrays.asList(files));
}
} }
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored
@ -167,6 +186,7 @@ public class JacocoReportOperation extends AbstractOperation<JacocoReportOperati
/** /**
* Configure the operation from a {@link BaseProject}. * Configure the operation from a {@link BaseProject}.
*/ */
@Override
public JacocoReportOperation fromProject(BaseProject project) { public JacocoReportOperation fromProject(BaseProject project) {
this.project = project; this.project = project;
return this; return this;
@ -180,6 +200,39 @@ public class JacocoReportOperation extends AbstractOperation<JacocoReportOperati
return this; return this;
} }
private int instrument(final File src, final File dest) throws IOException {
//noinspection ResultOfMethodCallIgnored
dest.getParentFile().mkdirs();
try (InputStream input = Files.newInputStream(src.toPath())) {
try (OutputStream output = Files.newOutputStream(dest.toPath())) {
return instrumenter.instrumentAll(input, output,
src.getAbsolutePath());
}
} catch (final IOException e) {
//noinspection ResultOfMethodCallIgnored
dest.delete();
throw e;
}
}
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
private int instrumentRecursive(final File src, final File dest)
throws IOException {
var total = 0;
if (src.isDirectory()) {
var listFiles = src.listFiles();
if (listFiles != null) {
for (var child : listFiles) {
total += instrumentRecursive(child,
new File(dest, child.getName()));
}
}
} else {
total += instrument(src, dest);
}
return total;
}
private ExecFileLoader loadExecFiles() throws IOException { private ExecFileLoader loadExecFiles() throws IOException {
var loader = new ExecFileLoader(); var loader = new ExecFileLoader();
if (execFiles.isEmpty() && LOGGER.isLoggable(Level.WARNING) && !quiet) { if (execFiles.isEmpty() && LOGGER.isLoggable(Level.WARNING) && !quiet) {
@ -241,6 +294,7 @@ public class JacocoReportOperation extends AbstractOperation<JacocoReportOperati
return this; return this;
} }
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
private ISourceFileLocator sourceLocator() { private ISourceFileLocator sourceLocator() {
var multi = new MultiSourceFileLocator(tabWidth); var multi = new MultiSourceFileLocator(tabWidth);

View file

@ -17,11 +17,10 @@
package rife.bld.extension; package rife.bld.extension;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class JacocoReportOperationTest { class JacocoReportOperationTest {
@Test @Test
void executeTest() { void executeTest() {
assertThat(true).isTrue(); // TODO
} }
} }