Skip to content

Commit

Permalink
Enhanced to support Gradle 4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
stevesaliman committed Jun 21, 2017
1 parent 458deb3 commit fa0edd5
Show file tree
Hide file tree
Showing 13 changed files with 90 additions and 47 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,12 @@
Changes for 4.5.0
=================
Prior to version 4.0, Gradle put the compiled class files from Java, Groovy, and
Scala sources into the same directory (`build/classes/main`), Starting with
Gradle 4.0, each language gets its own directory (`build/classes/java/main`,
`build/classes/groovy/main`, etc.) for compiled classes. The Cobertura plugin
now adds all of the correct directories based on which version of Gradle you are
running, and which plugins have been applied.

Changes for 2.4.0
=================
- Changed the way auxiliaryClasspath is built. In prior versions, it was
Expand Down
6 changes: 6 additions & 0 deletions README.md
Expand Up @@ -5,6 +5,12 @@ page for complete details on how to use this plugin.

News
====
### June 20, 2017
Version 2.5.0 now supports Gradle 4.0. In particular, the plugin has been
enhanced to be aware of where Gradle 4.0 is putting class files. Prior versions
of the plugin will run in Gradle 4.0, but it might not run correctly. See the
[CHANGELOG](http://github.com/stevesaliman/gradle-cobertura-plugin/blob/master/CHANGELOG.md)
for more details.
### December 22, 2016
Version 2.4.0 now builds under Gradle 3.2. It also introduces a change to the
way the auxiliaryClasspath is set up. Previously, if you wanted to add to
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Expand Up @@ -27,7 +27,7 @@ sourceCompatibility = '1.6'
targetCompatibility = '1.6'

// Release version that won't conflict with the bintray plugin
def releaseVersion = "2.4.0"
def releaseVersion = "2.5.0"
// variables that configure the Maven upload
group = "net.saliman"
archivesBaseName = "gradle-cobertura-plugin"
Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Sat Feb 11 09:40:32 MST 2017
#Tue Jun 20 19:19:31 MDT 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-bin.zip
6 changes: 3 additions & 3 deletions gradlew
Expand Up @@ -33,11 +33,11 @@ DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn ( ) {
warn () {
echo "$*"
}

die ( ) {
die () {
echo
echo "$*"
echo
Expand Down Expand Up @@ -155,7 +155,7 @@ if $cygwin ; then
fi

# Escape application args
save ( ) {
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
Expand Down
Expand Up @@ -20,7 +20,8 @@ class CoberturaExtension {

/**
* Directories under the base directory containing classes to be
* instrumented. Defaults to [project.sourceSets.main.classesDir.path]
* instrumented. Defaults to the names of each directory in
* [project.sourceSets.main.classesDirs]
*/
List<String> coverageDirs

Expand Down Expand Up @@ -85,7 +86,7 @@ class CoberturaExtension {

/**
* Files to add to the classpath when instrumenting. We'll always use
* project.sourceSets.main.output.classesDir and
* project.sourceSets.main.output.classesDirs and
* project.sourceSets.main.compileClasspath for Java projects, and
* ${project.buildDir.path}/intermediates/classes/${classesDir},
* project.configurations.getByName("compile") and ,
Expand Down Expand Up @@ -497,13 +498,31 @@ class CoberturaExtension {
project.plugins.apply(JavaPlugin)
project.logger.info "Creating cobertura extension for java project ${project.name}"

coverageDirs = [project.sourceSets.main.output.classesDir.path]
// Set the auxiliaryClasspath to defaults. This is the classpath
// cobertura uses for resolving classes while instrumenting.
if ( auxiliaryClasspath != null ) {
auxiliaryClasspath += project.files project.sourceSets.main.output.classesDir
// As of Gradle 4, Java, Groovy, and Scala files were compiled into
// the different directories. We know we're in Gradle 4 if the output
// has a 'classesDirs' property, which is a FileCollection.
if ( project.sourceSets.main.output.hasProperty('classesDirs') ) {
coverageDirs = []
def outputClassesDirs = project.sourceSets.main.output.classesDirs
outputClassesDirs.each {
coverageDirs << it.path
}
if ( auxiliaryClasspath != null ) {
auxiliaryClasspath.add(outputClassesDirs)
} else {
auxiliaryClasspath = outputClassesDirs
}
} else {
auxiliaryClasspath = project.files project.sourceSets.main.output.classesDir
// Prior to Gradle 4, the 3 kinds of files were compiled into a
// single directory represented by a File.
coverageDirs = [project.sourceSets.main.output.classesDir.path]
// Set the auxiliaryClasspath to defaults. This is the classpath
// cobertura uses for resolving classes while instrumenting.
if ( auxiliaryClasspath != null ) {
auxiliaryClasspath += project.files project.sourceSets.main.output.classesDir
} else {
auxiliaryClasspath = project.files project.sourceSets.main.output.classesDir
}
}
auxiliaryClasspath = auxiliaryClasspath.plus(project.sourceSets.main.compileClasspath)

Expand Down
Expand Up @@ -72,7 +72,7 @@ class CoberturaPlugin implements Plugin<PluginAware> {
static final String COBERTURA_REPORT_TASK_NAME = 'coberturaReport'
static final String COBERTURA_CHECK_TASK_NAME = 'coberturaCheck'

def void apply(PluginAware pluginAware) {
void apply(PluginAware pluginAware) {
if ( pluginAware instanceof Project ) {
doApply(pluginAware)
} else if ( pluginAware instanceof Settings ) {
Expand All @@ -88,7 +88,7 @@ class CoberturaPlugin implements Plugin<PluginAware> {
}
}

def void doApply(Project project) {
void doApply(Project project) {
if ( project.plugins.hasPlugin(CoberturaPlugin) ) {
project.logger.info("Project ${project.name} already has the cobertura plugin")
return
Expand Down Expand Up @@ -179,8 +179,9 @@ class CoberturaPlugin implements Plugin<PluginAware> {
// determine of we need reports or not.
coberturaTask.dependsOn reportTask

// Create the checkCoverage task. This task, when invoked, indicates that
// users want to check coverage levels, but it does not run any tests..
// Create the checkCoverage task. This task, when invoked, indicates
// that users want to check coverage levels, but it does not run any
// tests..
project.tasks.create(name: COBERTURA_CHECK_TASK_NAME,
group: 'Cobertura', type: DefaultTask)
Task checkCoverageTask = project.tasks.getByName(COBERTURA_CHECK_TASK_NAME)
Expand All @@ -189,8 +190,8 @@ class CoberturaPlugin implements Plugin<PluginAware> {
// report
checkCoverageTask.dependsOn reportTask

// Create the instrument task that will instrument code. At the moment, it
// is disabled.
// Create the instrument task that will instrument code. At the moment,
// it is disabled.
project.tasks.create(name: InstrumentTask.NAME,
type: InstrumentTask,
{
Expand All @@ -212,8 +213,8 @@ class CoberturaPlugin implements Plugin<PluginAware> {
copyDatafileTask.enabled = false
copyDatafileTask.dependsOn instrumentTask

// Create the generateCoberturaReport task that will generate the reports.
// Like the others, it starts out disabled.
// Create the generateCoberturaReport task that will generate the
// reports. Like the others, it starts out disabled.
project.tasks.create(name: GenerateReportTask.NAME,
type: GenerateReportTask,
{
Expand All @@ -233,8 +234,8 @@ class CoberturaPlugin implements Plugin<PluginAware> {
}
}

// Create the performCoverageCheck task that will do the work of checking
// the coverage levels, and you guessed it, it is disabled.
// Create the performCoverageCheck task that will do the work of
// checking the coverage levels, and you guessed it, it is disabled.
project.tasks.create(name: PerformCoverageCheckTask.NAME,
type: PerformCoverageCheckTask,
{
Expand Down
Expand Up @@ -8,15 +8,15 @@ import java.lang.reflect.Method
/**
* Wrapper for Cobertura's main classes.
*/
public class CoberturaRunner {
class CoberturaRunner {

private Set<File> classpath

public CoberturaRunner withClasspath(Set<File> classpath) {
CoberturaRunner withClasspath(Set<File> classpath) {
return new CoberturaRunner(classpath: classpath)
}

public void instrument(CoberturaExtension configuration,
void instrument(CoberturaExtension configuration,
String baseDir,
String destinationDir,
List<String> instrumentDirs) {
Expand Down Expand Up @@ -85,14 +85,16 @@ public class CoberturaRunner {
// </path>

args.addAll(instrumentDirs)
// System.out.println("---------------- args:")
// System.out.println("${args}")
if ( compareVersions(configuration.coberturaVersion, "2.1.0") > -1 ) {
executeCobertura("net.sourceforge.cobertura.instrument.InstrumentMain", "instrument", false, args)
} else {
executeCobertura("net.sourceforge.cobertura.instrument.Main", "main", false, args)
}
}

public void generateCoverageReport(CoberturaExtension configuration,
void generateCoverageReport(CoberturaExtension configuration,
String format,
List<String> sourceDirectories) throws Exception {
List<String> args = new ArrayList<String>()
Expand All @@ -117,7 +119,7 @@ public class CoberturaRunner {
}
}

public int checkCoverage(CoberturaExtension configuration) throws Exception {
int checkCoverage(CoberturaExtension configuration) throws Exception {
List<String> args = new ArrayList<String>()
args.add("--datafile")
args.add(configuration.coverageOutputDatafile.path)
Expand Down Expand Up @@ -203,15 +205,15 @@ public class CoberturaRunner {
// System.out.println("${args}")
// We need to replace the classloader for the thread with one that finds
// Cobertura's dependencies first.
ClassLoader prevCl = Thread.currentThread().getContextClassLoader();
ClassLoader prevCl = Thread.currentThread().getContextClassLoader()

if ( classpath ) {
def urls = classpath.collect { it.toURI().toURL() }
ClassLoader cl = new ChildFirstUrlClassLoader(urls as URL[], prevCl)
Thread.currentThread().setContextClassLoader(cl);
Thread.currentThread().setContextClassLoader(cl)
}

def SecurityManager oldSm = System.getSecurityManager()
SecurityManager oldSm = System.getSecurityManager()
CoberturaSecurityManager sm = new CoberturaSecurityManager(oldSm)
def exitStatus = 0

Expand All @@ -234,7 +236,7 @@ public class CoberturaRunner {
// Restore the classLoader. Then, if we're dealing with a Security
// Exception (checkCoverage did a System.exit), set the exit status
// to whatever code the security manager says should be returned.
Thread.currentThread().setContextClassLoader(prevCl);
Thread.currentThread().setContextClassLoader(prevCl)
if ( useSecurityManager ) {
System.setSecurityManager(oldSm)
exitStatus = sm.exitStatus
Expand All @@ -257,11 +259,11 @@ public class CoberturaRunner {
return true
}
if ( !InvocationTargetException.class.isAssignableFrom(e.class) ) {
return false;
return false
}
def cause = e.targetException
if ( cause == null ) {
return false;
return false
}
return SecurityException.class.isAssignableFrom(cause.class)
}
Expand Down
Expand Up @@ -33,10 +33,14 @@ class CoberturaRunnerTest {
def configuration = new CoberturaExtension(project)
configuration.coverageInputDatafile = new File("${destDir.absolutePath}/cobertura.ser")

runner.instrument(configuration, "build/classes/main", destDir.absolutePath, ['.'])
File classesDir = new File('build/classes/main')
def x = ['build/classes/java/main', 'build/classes/groovy/main']
runner.instrument(configuration, null, destDir.absolutePath, x)

File classesDir = new File('build/classes/java/main')
int count = 0
classesDir.eachFileMatch FileType.FILES, ~/.*\.class/, { count++ }
classesDir = new File('build/classes/groovy/main')
classesDir.eachFileMatch FileType.FILES, ~/.*\.class/, { count++ }
int instrumentedCount = 0
destDir.eachFileMatch FileType.FILES, ~/.*\.class/, { instrumentedCount++ }
assertEquals(count, instrumentedCount)
Expand Down
5 changes: 3 additions & 2 deletions testclient/calculator/build.gradle
@@ -1,9 +1,10 @@
#!groovy
apply plugin: 'java'
apply plugin: 'groovy'
apply plugin: 'scala'
apply plugin: 'net.saliman.cobertura'
apply plugin: 'eclipse'
apply plugin: 'idea'
//apply plugin: 'eclipse'
//apply plugin: 'idea'
apply plugin: 'maven'

repositories {
Expand Down
Expand Up @@ -12,7 +12,7 @@
public class CalculatorDivideTest {
private Calculator calculator = new Calculator();

@Test
@Test(expected=ArithmeticException.class)
public void divideByZero() {
assertEquals(2, calculator.divide(4, 0));
}
Expand Down
15 changes: 8 additions & 7 deletions usage.md
Expand Up @@ -5,7 +5,7 @@ build.gradle file.

```groovy
plugins {
id 'net.saliman.cobertura' version '2.4.0'
id 'net.saliman.cobertura' version '2.5.0'
}
```

Expand All @@ -20,14 +20,15 @@ buildscript {
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
}
dependencies {
classpath "net.saliman:gradle-cobertura-plugin:2.4.0"
classpath "net.saliman:gradle-cobertura-plugin:2.5.0"
}
}
apply plugin: 'net.saliman.cobertura'
```

If you are using this plugin on an android project, you must apply it after the
android plugin.
If you are using this plugin on a java, groovy, or scala project, it is probably
best to apply it after those plugins. If you are using this plugin on an
android project, you must apply it after the android plugin.

If you are using this plugin on a project that does *not* use slf4j, and you
run into ```ClassNotFoundException``` issues, you will need to add a version
Expand Down Expand Up @@ -105,16 +106,16 @@ following options:
- ```auxiliaryClasspath = <FileCollection>```: You can add files and directories
to the classpath that Cobertura uses while instrumenting your classes. The
plugin will always include certain directories, based on the type of project.
Java projects will always include project.sourceSets.main.output.classesDir +
Java projects will always include project.sourceSets.main.output.classesDirs +
project.sourceSets.main.compileClasspath. Android projects will always include
${project.buildDir.path}/intermediates/classes/${classesDir} +
project.configurations.getByName("compile") +
project.configurations.getByName("${androidVariant}Compile"))).
There is no need to include them again.

- ```coverageDirs = [ <dirnames> ]```: An array of directories under the base
directory containing classes to be instrumented. The default is
[ project.sourceSets.main.classesDir.path ]
directory containing classes to be instrumented. The default is the names
of each directory in [ project.sourceSets.main.classesDirs ]

- ```coverageInputDatafile = <file>```: The file object referring to the
.ser file to create during instrumentation.
Expand Down

0 comments on commit fa0edd5

Please sign in to comment.