Skip to content
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

Merged
merged 42 commits into from Dec 21, 2016

Conversation

bmuschko
Copy link
Contributor

@bmuschko bmuschko commented Dec 7, 2016

Please see issue #824 for more information.

Design decisions to consider when reviewing:

  • Configuration options have been aligned with terminology from the JaCoCo document to allow users to pin back options to Gradle plugin.
  • Pre-defined values for certain configuration options have not been represented by enums. This is to ensure best forward and backward compatibility of JaCoCo versions without having to change plugin code.
  • Violation checks have been implemented as separate task to ensure fine-grained control for the end user. The representing task has not be hooked up with check to avoid strong coupling.

Benjamin Muschko added 30 commits December 1, 2016 18:15
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
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@eriwen
Copy link
Contributor

eriwen commented Dec 7, 2016

I'll volunteer to do this review.

@eriwen eriwen self-assigned this Dec 7, 2016
@eriwen eriwen self-requested a review December 12, 2016 21:58
@eriwen eriwen assigned bmuschko and unassigned eriwen Dec 12, 2016
Copy link
Contributor

@eriwen eriwen left a 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'
Copy link
Contributor

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.

Copy link
Contributor Author

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>
Copy link
Contributor

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);
Copy link
Contributor

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 {
Copy link
Contributor

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 {
Copy link
Contributor

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).

Copy link
Member

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);
Copy link
Contributor

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

Copy link
Contributor Author

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.

@eriwen
Copy link
Contributor

eriwen commented Dec 20, 2016

@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

@wolfs
Copy link
Member

wolfs commented Dec 20, 2016

@eriwen That is just the case since all Jacoco tests are disabled on Java 9. Just the new tests have not yet been ignored. Jacoco support for Java 9 would be handled by #1006.

@bmuschko
Copy link
Contributor Author

@eriwen I'll ignore running those tests on Java 9 for now and will address Java 9 support separately.

Copy link
Contributor

@eriwen eriwen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@bmuschko bmuschko added this to the 4.0 milestone Dec 20, 2016
@bmuschko bmuschko merged commit c7abc17 into master Dec 21, 2016
@bmuschko bmuschko deleted the bm-jacoco-enforce-metrics branch December 21, 2016 15:25
Copy link
Member

@big-guy big-guy left a 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> {
Copy link
Member

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.

Copy link
Contributor Author

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)
Copy link
Member

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?

Copy link
Contributor Author

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?

Copy link
Member

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 {
Copy link
Member

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
Copy link
Member

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?

Copy link
Contributor Author

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[]
Copy link
Member

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?

Copy link
Contributor Author

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.
Copy link
Member

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)

Copy link
Contributor Author

@bmuschko bmuschko Jan 3, 2017

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();
Copy link
Member

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.

Copy link
Contributor Author

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>
Copy link
Member

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?

Copy link
Contributor Author

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.
Copy link
Member

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?

Copy link
Contributor Author

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);
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants