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

Added extended reports filtering #581

Merged
merged 13 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[versions]

intellij-coverage = "1.0.752"
intellij-coverage = "1.0.753"
junit = "5.9.0"
kotlinx-bcv = "0.13.2"
kotlinx-dokka = "1.8.10"
Expand Down
26 changes: 15 additions & 11 deletions kover-cli/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,22 @@ For information about offline instrumentation, [see](../offline-instrumentation#
| --include <class-name> | instrument only specified classes, wildcards `*` and `?` are acceptable | | + |

### Generating reports

Allows you to generate HTML and XML reports from the existing binary report.

`java -jar kover-cli.jar report [<binary-report-path> ...] --classfiles <class-file-path> [--exclude <class-name>] [--excludeAnnotation <annotation-name>] [--html <html-dir>] [--include <class-name>] --src <sources-path> [--title <html-title>] [--xml <xml-file-path>]`

| Option | Description | Required | Multiple |
|---------------------------------------|---------------------------------------------------------------------------------------------------------|:--------:|:--------:|
| `<binary-report-path>` | list of binary reports files | | + |
| --classfiles <class-file-path> | location of the compiled class-files root (must be original and not instrumented) | + | + |
| --exclude <class-name> | filter to exclude classes, wildcards `*` and `?` are acceptable | | + |
| --excludeAnnotation <annotation-name> | filter to exclude classes and functions marked by this annotation, wildcards `*` and `?` are acceptable | | + |
| --html <html-dir> | generate a HTML report in the specified path | | |
| --include <class-name> | filter to include classes, wildcards `*` and `?` are acceptable | | + |
| --src <sources-path> | location of the source files root | + | + |
| --title <html-title> | title in the HTML report | | |
| --xml <xml-file-path> | generate a XML report in the specified path | | |
| Option | Description | Required | Multiple |
|------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|:--------:|:--------:|
| `<binary-report-path>` | list of binary reports files | | + |
| --classfiles <class-file-path> | location of the compiled class-files root (must be original and not instrumented) | + | + |
| --exclude <class-name> | filter to exclude classes, wildcards `*` and `?` are acceptable | | + |
| --include <class-name> | filter to include classes, wildcards `*` and `?` are acceptable | | + |
| --excludeAnnotation <exclude-annotation-name> | filter to exclude classes and functions marked by this annotation, wildcards `*` and `?` are acceptable. Excludes have priority over includes | | + |
| --includeAnnotation <include-annotation-name> | filter to include classes marked by this annotation, wildcards `*` and `?` are acceptable | | + |
| --excludeInheritedFrom <exclude-ancestor-name> | filter to exclude classes extending the specified class or implementing an interface, wildcards `*` and `?` are acceptable | | + |
| --includeInheritedFrom <include-ancestor-name> | filter to include only classes extending the specified class or implementing an interface, wildcards `*` and `?` are acceptable | | + |
| --html <html-dir> | generate a HTML report in the specified path | | |
| --src <sources-path> | location of the source files root | + | + |
| --title <html-title> | title in the HTML report | | |
| --xml <xml-file-path> | generate a XML report in the specified path | | |
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ internal class OfflineInstrumentCommand : Command {
val filters = ClassFilters(
includeClasses.toSet(),
excludeClasses.toSet(),
excludeAnnotation.toSet()
excludeAnnotation.toSet(),
emptySet(),
emptySet(),
emptySet()
)

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,32 @@ internal class ReportCommand : Command {

@Option(
name = "--excludeAnnotation",
usage = "filter to exclude classes and functions marked by this annotation, wildcards `*` and `?` are acceptable",
metaVar = "<annotation-name>"
usage = "filter to exclude classes and functions marked by this annotation, wildcards `*` and `?` are acceptable. Excludes have priority over includes",
metaVar = "<exclude-annotation-name>"
)
private var excludeAnnotation: MutableList<String> = ArrayList()

@Option(
name = "--includeAnnotation",
usage = "filter to include classes marked by this annotation, wildcards `*` and `?` are acceptable. Excludes have priority over includes.",
metaVar = "<include-annotation-name>"
)
private var includeAnnotation: MutableList<String> = ArrayList()

@Option(
name = "--excludeInheritedFrom",
usage = "filter to exclude classes extending the specified class or implementing an interface, wildcards `*` and `?` are acceptable. Excludes have priority over includes",
metaVar = "<exclude-ancestor-name>"
)
private var excludeInheritedFrom: MutableList<String> = ArrayList()

@Option(
name = "--includeInheritedFrom",
usage = "filter to include only classes extending the specified class or implementing an interface, wildcards `*` and `?` are acceptable. Excludes have priority over includes",
metaVar = "<include-ancestor-name>"
)
private var includeInheritedFrom: MutableList<String> = ArrayList()

override val name: String = "report"

override val description: String = "Generates human-readable reports in various formats from binary report files"
Expand All @@ -79,7 +100,10 @@ internal class ReportCommand : Command {
val filters = ClassFilters(
includeClasses.toSet(),
excludeClasses.toSet(),
excludeAnnotation.toSet()
includeAnnotation.toSet(),
excludeAnnotation.toSet(),
includeInheritedFrom.toSet(),
excludeInheritedFrom.toSet()
)

var fail = false
Expand Down
12 changes: 9 additions & 3 deletions kover-features-jvm/api/kover-features-jvm.api
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,22 @@ public final class kotlinx/kover/features/jvm/BoundViolation {
}

public final class kotlinx/kover/features/jvm/ClassFilters {
public fun <init> (Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;)V
public fun <init> (Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;)V
public final fun component1 ()Ljava/util/Set;
public final fun component2 ()Ljava/util/Set;
public final fun component3 ()Ljava/util/Set;
public final fun copy (Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;)Lkotlinx/kover/features/jvm/ClassFilters;
public static synthetic fun copy$default (Lkotlinx/kover/features/jvm/ClassFilters;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;ILjava/lang/Object;)Lkotlinx/kover/features/jvm/ClassFilters;
public final fun component4 ()Ljava/util/Set;
public final fun component5 ()Ljava/util/Set;
public final fun component6 ()Ljava/util/Set;
public final fun copy (Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;)Lkotlinx/kover/features/jvm/ClassFilters;
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 OK that we break the public ABI of a data class like this? Will we be allowed to do so after 1.0 release?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Is there a problem with data classes? They can be made non-data classes, however, then it will not be very convenient to use them (toString is convenient for debugging)

Copy link
Member

Choose a reason for hiding this comment

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

Standard problems with incompatible constructors, copy(), etc

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Manually override toString and equals/hashCode?

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 know, if this class is not expected to be called from different versions, than it's OK

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is expected that the Kover Gradle Plugin and Kover Features versions should be the same.

public static synthetic fun copy$default (Lkotlinx/kover/features/jvm/ClassFilters;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;ILjava/lang/Object;)Lkotlinx/kover/features/jvm/ClassFilters;
public fun equals (Ljava/lang/Object;)Z
public final fun getExcludeAnnotation ()Ljava/util/Set;
public final fun getExcludeClasses ()Ljava/util/Set;
public final fun getExcludeInheritedFrom ()Ljava/util/Set;
public final fun getIncludeAnnotation ()Ljava/util/Set;
public final fun getIncludeClasses ()Ljava/util/Set;
public final fun getIncludeInheritedFrom ()Ljava/util/Set;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,56 @@ public data class ClassFilters(
*/
public val excludeClasses: Set<String>,
/**
* Classes that have at least one of the annotations specified in this field are not filtered.
* Classes that have at least one of the annotations specified in this field are present in the report.
* All other classes that are not marked with at least one of the specified annotations are not included in the report.
*
*
* If inclusion and exclusion rules are specified at the same time, then excludes have priority over includes.
* This means that even if a class is annotated with both annotations from 'exclude' and 'include', it will be excluded from the report.
*
*/
public val includeAnnotation: Set<String>,
/**
* Classes that have at least one of the annotations specified in this field are not present in the report.
*
*
* If inclusion and exclusion rules are specified at the same time, then excludes have priority over includes.
* This means that even if a class is annotated with both annotations from 'exclude' and 'include', it will be excluded from the report.
*
*/
public val excludeAnnotation: Set<String>,
/**
*
* Include only classes extending at least one of the specified classes or implementing at least one of the interfaces.
* The class itself with the specified name is not included in the report.
*
*
* The entire inheritance tree is analyzed; a class may inherit the specified class/interface indirectly and still be included in the report, unless the specified class/interface is located outside of the application (see below).
*
*
* The following classes and interfaces can be specified in arguments:
*
* * classes and interfaces declared in the application
* * classes and interfaces declared outside the application, if they are directly inherited or implemented by any type from the application
*
*
* Due to technical limitations, if a specified class or interface is not declared in the application and not extended/implemented directly by one of the application types, such a filter will have no effect.
*/
public val includeInheritedFrom: Set<String>,
/**
*
* Exclude classes extending at least one of the specified classes or implementing at least one of the interfaces.
* The class itself with the specified name is not excluded from the report.
*
* The entire inheritance tree is analyzed; a class may inherit the specified class/interface indirectly and still be included in the report, unless the specified class/interface is located outside of the application (see below).
*
* The following classes and interfaces can be specified in arguments:
*
* * classes and interfaces declared in the application
* * classes and interfaces declared outside the application, however they are directly inherited or implemented by any type from the application
*
*
* Due to technical limitations, if a specified class or interface is not declared in the application and not extended/implemented directly by one of the application types, such a filter will have no effect.
*/
public val excludeAnnotation: Set<String>
public val excludeInheritedFrom: Set<String>
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,17 @@ import java.util.regex.Pattern

internal fun ClassFilters.convert(): Filters {
return Filters(
convert(includeClasses),
convert(excludeClasses),
emptyList(),
convert(excludeAnnotation),
emptyList(),
emptyList()
includeClasses.toRegexp(),
excludeClasses.toRegexp(),
includeAnnotation.toRegexp(),
excludeAnnotation.toRegexp(),
includeInheritedFrom.toRegexp(),
excludeInheritedFrom.toRegexp()
)
}

private fun convert(templates: Set<String>): List<Pattern> {
val patterns = ArrayList<Pattern>(templates.size)
for (template in templates) {
patterns.add(Pattern.compile(template.wildcardsToRegex()))
}
return patterns
private fun Collection<String>.toRegexp(): List<Pattern> {
return map { template -> Pattern.compile(template.wildcardsToRegex()) }
}

/**
Expand Down
2 changes: 2 additions & 0 deletions kover-gradle-plugin/api/kover-gradle-plugin.api
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ public abstract interface class kotlinx/kover/gradle/plugin/dsl/KoverReportFilte
public abstract fun classes ([Ljava/lang/String;)V
public abstract fun classes ([Lorg/gradle/api/provider/Provider;)V
public abstract fun getProjects ()Lorg/gradle/api/provider/SetProperty;
public abstract fun inheritedFrom ([Ljava/lang/String;)V
public abstract fun inheritedFrom ([Lorg/gradle/api/provider/Provider;)V
public abstract fun packages (Ljava/lang/Iterable;)V
public abstract fun packages (Lorg/gradle/api/provider/Provider;)V
public abstract fun packages ([Ljava/lang/String;)V
Expand Down
Loading