New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce task for JaCoCo plugin for enforcing code coverage metrics #983
Conversation
Allows for better forward and backward capability in case JaCoCo decides to introduce new values or change existing ones.
Makes it easier for users to map configuration options to Jacoco documentation. Aligns the configuration options with Maven plugin and Ant tasks.
Results in better configurability for end user and decouples report generation from coverage verification.
* | ||
* @since 4.0 | ||
*/ | ||
@CacheableTask |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC this task declares no output, and thus won't ever be cached.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
I'll volunteer to do this review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall changes look very good. I have noted 2 things to reconsider: A TODO comment and the jacocoTestCheck
task name.
I really appreciate you breaking this change into many small commits — that allowed me to follow along very well and I think made for a more effective review.
onlyIf(new Spec<Task>() { | ||
@Override | ||
public boolean isSatisfiedBy(Task element) { | ||
//TODO SF it should be 'any' instead of 'all' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should address this TODO
comment or remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -236,6 +241,16 @@ | |||
</td> | |||
<td>Generates code coverage report for the test task.</td> | |||
</tr> | |||
<tr> | |||
<td> | |||
<literal>jacocoTestCheck</literal> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: this task name doesn't represent what it's for IMO. Perhaps jacocoVerificationCheck
or jacocoEnforceThresholds
or something.
@@ -247,4 +249,10 @@ public File call() { | |||
} | |||
}); | |||
} | |||
|
|||
private void addDefaultCheckTask(final Test task) { | |||
final JacocoCheck checkTask = project.getTasks().create("jacoco" + StringUtils.capitalise(task.getName()) + "Check", JacocoCheck.class); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same nitpick as elsewhere: jacocoTestCheck
seems like a confusing name to me. What name would make it very obvious what it's purpose was?
@@ -31,13 +34,14 @@ | |||
* @since 4.0 | |||
*/ | |||
@Incubating | |||
public interface JacocoViolationRule { | |||
public interface JacocoViolationRule extends Serializable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Silly question: why does this need to be Serializable
?
|
||
import org.gradle.test.fixtures.file.TestFile | ||
|
||
class JavaProjectUnderTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a really cool idea. We should do this elsewhere (not a part of this PR of course).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do this in other places already. Usually, they're called _Something_App. Look at all of the TestApp
classes or PlayApp
for other examples.
@@ -247,4 +249,10 @@ public File call() { | |||
} | |||
}); | |||
} | |||
|
|||
private void addDefaultCheckTask(final Test task) { | |||
final JacocoCheck checkTask = project.getTasks().create("jacoco" + StringUtils.capitalise(task.getName()) + "Check", JacocoCheck.class); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like we should add these jacoco*
tasks to a group so they're listed in gradle tasks
report
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. Also added a description
.
@bmuschko We may need to handle Java 9 in tandem with this. Nearly all of the tests failed for JaCoCo on Java 9: https://builds.gradle.org/viewLog.html?buildTypeId=Gradle_Branches_CoveragePhase_LinuxCoverage_LinuxJava19_8LinuxJava19&buildId=1958128 |
@eriwen I'll ignore running those tests on Java 9 for now and will address Java 9 support separately. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎅
jacocoVersion.compareTo(supportedJacocoVersion) == -1 | ||
}.asImmutable() | ||
|
||
private static class JacocoVersion implements Comparable<JacocoVersion> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we reuse VersionNumber
? You'd get a Comparable
for free.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the spirit of dog-fooding I'd like to avoid using the internal class VersionNumber
. That'll also make it easier to external the plugin later.
}.asImmutable() | ||
|
||
private static class JacocoVersion implements Comparable<JacocoVersion> { | ||
final static CHECK_INTRODUCED = new JacocoVersion(0, 6, 3) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be put outside of JacocoVersion
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a "pattern" described in Effective Java on page 76, chapter 4. What would be benefit of moving it out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nevermind. It only made sense if we were replacing JacocoVersion
for VersionNumber
.
|
||
import org.gradle.test.fixtures.file.TestFile | ||
|
||
class JavaProjectUnderTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do this in other places already. Usually, they're called _Something_App. Look at all of the TestApp
classes or PlayApp
for other examples.
jacocoTestCoverageVerification { | ||
violationRules { | ||
rule { | ||
$Sufficient.LINE_METRIC_COVERED_RATIO |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get a weird IntelliJ warning about this and the import above. Do you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've seen this before. Interestingly, it works if I import the class again - but the file didn't actually change. This looks like a bug in IntelliJ to me.
abstract class AbstractJacocoPluginCoverageVerificationVersionIntegrationTest extends MultiVersionIntegrationSpec { | ||
|
||
private final JavaProjectUnderTest javaProjectUnderTest = new JavaProjectUnderTest(testDirectory) | ||
protected final static String[] TEST_AND_JACOCO_COVERAGE_VERIFICATION_TASK_PATHS = [':test', ':jacocoTestCoverageVerification'] as String[] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it not enough to just run with :jacocoTestCoverageVerification
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The task :jacocoTestCoverageVerification
doesn't have any task dependencies. Without running the test
task first, we wouldn't have any execution data and therefore the verification would be SKIPPED
.
*/ | ||
|
||
/** | ||
* Implementations for Jacoco code coverage rules. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be helpful to provide links to Jacoco's docs on this (if there are any)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would feel kind of weird to link to the documentation page of the Ant task. That documentation page also doesn't have any anchors so users would have to scroll down to even find what they are looking for. It would probably confuse more than help.
* Gets all limits defined for this rule. Defaults to an empty list. | ||
*/ | ||
@Nested | ||
List<JacocoLimit> getLimits(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this works (but I would need to check...). I think we would end up looking for annotations on List
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Will use @Input
instead.
</para> | ||
<sample id="configViolationRules" dir="testing/jacoco/quickstart" title="Configuring violation rules"> | ||
<sourcefile file="build.gradle" snippet="violation-rules-configuration"/> | ||
</sample> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there any Jacoco docs we could link to too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment above.
/** | ||
* Gets the element for the rule as defined by | ||
* <a href="http://www.eclemma.org/jacoco/trunk/doc/api/org/jacoco/core/analysis/ICoverageNode.ElementType.html">org.jacoco.core.analysis.ICoverageNode.ElementType</a>. | ||
* Valid scope values are BUNDLE, PACKAGE, CLASS, SOURCEFILE and METHOD. Defaults to BUNDLE. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any kind of precedence here? e.g., if I define a limit for PACKAGE
and another limit for CLASS
, does one override the other?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about that. IMHO that's something the Ant task should handle for us.
@Input | ||
List<String> getIncludes(); | ||
|
||
void setExcludes(List<String> excludes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need javadoc on the setters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems to be a pattern we use across various plugins e.g.
- https://github.com/gradle/gradle/blob/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/FindBugsExtension.java#L94
- https://github.com/gradle/gradle/blob/master/subprojects/jacoco/src/main/java/org/gradle/testing/jacoco/plugins/JacocoPluginExtension.java#L81
That's why I didn't add it.
Please see issue #824 for more information.
Design decisions to consider when reviewing:
check
to avoid strong coupling.