• Stars
    star
    134
  • Rank 261,435 (Top 6 %)
  • Language
    Java
  • License
    Apache License 2.0
  • Created almost 10 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A Gradle plugin for JApicmp

JApicmp Gradle Plugin

Build Status Apache License 2

The japicmp-gradle-plugin provides binary compatibility reporting through JApicmp using Gradle.

Installation

This plugin requires Gradle 6+. Use the following snippet inside a Gradle build file:

plugins {
    id 'me.champeau.gradle.japicmp' version '0.4.1'
}

or (not recommended):

build.gradle
buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'me.champeau.gradle:japicmp-gradle-plugin:0.4.1'
    }
}
apply plugin: 'me.champeau.gradle.japicmp'

Configuration

The plugin provides a new task type: me.champeau.gradle.japicmp.JapicmpTask that you can use to compare two jars. This task exposes the following properties as part of its configuration:

oldClasspath

The classpath of the baseline library to compare. Type: FileCollection

newClasspath

The classpath of the current version of the library, which you want to check binary compatibility Type: FileCollection

oldArchives

The jar files which will be used as the baseline for comparison. Type: FileCollection.

newArchives

The jar files we want to analyze. Type: Type: FileCollection.

onlyModified

Outputs only modified classes/methods. If not set to true, all classes and methods are printed. Type: boolean. Default value: false

onlyBinaryIncompatibleModified

Outputs only classes/methods with modifications that result in binary incompatibility. Type: boolean. Default value: false

packageIncludes

List of package names to include, * can be used as wildcard. Type: List<String>

packageExcludes

List of package names to exclude, * can be used as wildcard. Type: List<String>

classIncludes

List of classes to include. Type: List<String>

classExcludes

List of classes to exclude. Type: List<String>

methodIncludes

List of methods to include. Type: List<String>

methodExcludes

List of methods to exclude. Type: List<String>

fieldIncludes

List of fields to include. Type: List<String>

fieldExcludes

List of fields to exclude. Type: List<String>

annotationIncludes

List of annotations to include. The string must begin with '@'. Type: List<String>

annotationExcludes

List of annotations to exclude. The string must begin with '@'. Type: List<String>

compatibilityChangeExcludes

List of compatibility changes to exclude, marking them as source and binary compatible. The string must match a value of the japicmp.model.JApiCompatibilityChange enum. Type: List<String>

accessModifier

Sets the access modifier level (public, package, protected, private). Type: String. Default value: public

failOnSourceIncompatibility

Fails if the changes result in source level incompatibility. Setting this to true also implicitly enables failOnModification. imType: boolean. Default value: false

failOnModification

When set to true, the build fails in case a modification has been detected. Type: boolean. Default value: false

xmlOutputFile

Path to the generated XML report. Type: File. Default value: null

htmlOutputFile

Path to the generated HTML report. Type: File. Default value: null

txtOutputFile

Path to the generated TXT report. Type: File. Default value: null

includeSynthetic

Synthetic classes and class members (like e.g. bridge methods) are not tracked per default. This new option enables the tracking of such kind of classes and class members

ignoreMissingClasses

Ignores all superclasses or interfaces that missing on the classpath. Default value: false

If you donโ€™t set oldArchives and newArchives, the plugin will infer them from the oldClasspath and newClasspath properties:

  • if you set the classpath to a configuration, the archives to compare will be the first level dependencies of that configuration

  • if you set the classpath to a simple file collection, all archives will be compared

Usage

Add the following to your build file:

tasks.register("japicmp", me.champeau.gradle.japicmp.JapicmpTask) {
    oldClasspath.from(files('path/to/reference.jar'))
    newClasspath.from(tasks.named('jar'))
    onlyModified = true
    failOnModification = true
    txtOutputFile = layout.buildDirectory.file("reports/japi.txt")
}

JApiCompatibilityChange filtering

The plugin supports simple exclusion for identified compatibility changes, turning these into binary and source compatible during API comparison:

tasks.register("japicmp", me.champeau.gradle.japicmp.JapicmpTask) {
   ...
   compatibilityChangeExcludes = [ "METHOD_NEW_DEFAULT" ]
}

The JApiCompatibilityChange enum from japicmp represents the list of identified compatibility changes which can be excluded. For simplicity, the plugin is configured with a List<String> instead.

Custom filtering

The plugin supports adding filters for bytecode members before they are considered for API comparison:

tasks.register("japicmp", me.champeau.gradle.japicmp.JapicmpTask) {
   ...
   addIncludeFilter(MyCustomFilter)
   addExcludeFilter(MyOtherFilter)
}

where MyIncludeFilter and MyExcludeFilter are classes implementing types inheriting from japicmp.filter.Filter.

For example, adding the following filter as an exclude filter will hide fields that are annotated with @Custom or have a name that contains Custom from the API comparison:

class MyOtherFilter implements FieldFilter {
    @Override
    boolean matches(CtField field) {
        return field.hasAnnotation("Custom") || field.name.contains("Custom")
    }
}

Custom reports and failure conditions

The plugin supports a DSL to generate custom reports based on the API comparison result. This has several advantages:

  • you can generate a report that focuses only on your public API, leaving the internal APIs out

  • you can implement custom rules to determine if the build should fail or not

  • the report can be presented to users and provide guidance for migration from one version to the other

Configuration

The report can be configured using the richReport block:

tasks.register("japicmp", me.champeau.gradle.japicmp.JapicmpTask) {
   ...
   richReport {
      ...
   }
}

Options for the rich report are:

renderer

The renderer used to generate the report. By default, it uses the GroovyReportRenderer

includedClasses

A list of strings representing inclusion patterns (interpreted as regular expressions). Only classes matching this pattern will be included.

excludedClasses

A list of strings representing exclusion patterns. If a class fully qualified name matches any of those patterns, it will not be included.

destinationDir

the directory where to store the report

reportName

file name of the generated report (defaults to rich-report.html)

title

a title for the report

description

a description for the report

addDefaultRules

a boolean, indicating whether the default rules should be added or not.

If no rules are explicitly defined, the default rules are applied. If any rule is added, the default rules wonโ€™t be applied unless addDefaultRules is set to true.

Custom rules

Rules are used to add violations to the report. The "violation" term must be taken in a simple sense, as it represents data to be shown in the report, whether itโ€™s a critical violation or just information.

A violation consists of a triplet (member, severity, explanation), that will be seen in the report. For example, if a binary incompatibility is found, you can create a violation using:

Violation.notBinaryCompatible(member)

which will automatically assign it to the error severity, leading in a build failure. However, it is possible to create any kind of violation, and even accept binary incompatible changes.

Rules can be applied to 3 different levels:

  • all members (a generic rule applied unconditionnaly)

  • on specific change types (NEW, REMOVED, UNCHANGED, MODIFIED), see JApiChangeStatus

  • on specific compatibility change descriptors (see JApiCompatibilityChange)

Rules are executed in the following order:

  1. status change first

  2. specific compatibility change

  3. generic rules

For example, imagine that we want to check that all new methods are annotated with @Incubating (this is a rule in the Gradle project). Then, you need to create a rule class which will implement that check:

class IncubatingMissingRule implements ViolationRule {
    @Override
    Violation maybeViolation(final JApiCompatibility member) {
        if (member instanceof JApiMethod) {
            if (!member.annotations.find { it.fullyQualifiedName == 'org.gradle.api.Incubating' }) {
                if (!member.jApiClass.annotations.find {
                    it.fullyQualifiedName == 'org.gradle.api.Incubating'
                }) {
                    Violation.error(member, "New method is not annotated with @Incubating")
                }
            }
        }
    }
}

and then you need to configure the report to use that rule:

richReport {
   addRule(JApiChangeStatus.NEW, IncubatingMissingRule)
}

Rules can take arguments, but those are limited to Map<String, String>. For example, the following rule will mark a binary breaking change as an error, unless it is reviewed and accepted. The list of acceptations is passed as an argument to the rule:

class AcceptedRegressionRule implements ViolationRule {
    private final Map<String, String> acceptedViolations

    public AcceptedRegressionRule(Map<String, String> params) {
        acceptedViolations = params
    }

    @Override
    Violation maybeViolation(final JApiCompatibility member) {
        if (!member.binaryCompatible) {
            def acceptation = acceptedViolations[Violation.describe(member)]
            if (acceptation) {
                Violation.accept(member, acceptation)
            } else {
                Violation.notBinaryCompatible(member)
            }
        }
    }
}

and hereโ€™s how the rule is applied:

richReport {
   addRule(AcceptedRegressionRule, acceptedViolations)
}

Setup and post-process rules

Since release 0.2.2, the plugin also supports setup and post-process rules. Setup rules allow setting up some global context that can be accessed by rules extending AbstractContextAwareViolationRule. This can be useful when you need to share data between rules, and perform a final check in a post-process rule.

Setup rules need to implement SetupRule:

class MySetupRule implements SetupRule {

    @Override
    void execute(final ViolationCheckContext violationCheckContext) {
        // this is going to be executed before any other rule is executed
        violationCheckContext.userData.executed = false
    }
}

and declared using addSetupRule:

richReport {
   addSetupRule(MySetupRule)
}

Then the context can be accessed in rules implementing AbstractContextAwareViolationRule:

class ContextAwareRule extends AbstractContextAwareViolationRule {

    @Override
    Violation maybeViolation(final JApiCompatibility member) {
        // this rule is accessing the global context and can mutate user data
        context.userData.executed = true

        return null
    }
}

And then a post-process rule has access to the user data, and can also mutate the actual list of violations per class, before the report is generated:

class MyTearDownRule implements PostProcessViolationsRule {

    @Override
    void execute(final ViolationCheckContextWithViolations violationCheckContextWithViolations) {
        // this rule is executed once all checks have been performed, just before the generation
        // of the report
        // it gives the opportunity to add additional violations, or filter them, or fail
        // with a custom error
        assert violationCheckContextWithViolations.userData.executed == true
        assert !violationCheckContextWithViolations.violations.isEmpty()
    }
}

It needs to be wired in using the addPostProcessRule hook:

richReport {
   addPostProcessRule(MySetupRule)
}

Avoiding multiple violations for the same class

Since 0.2.5, it is now possible to track which members have already resulted in a violation. Since rules are executed in order, and that you can have a rule applied for a status change and a generic rule applied on the same member, it was possible for a member to trigger multiple violations. To avoid this, you can make your rule extend AbstractRecordingSeenMembers. This rule requires the RecordSeenMembersSetup to be applied, and it will only add a violation, if no other violation for the same member was added before.

More Repositories

1

jmh-gradle-plugin

Integrates the JMH benchmarking framework with Gradle
Groovy
598
star
2

deck2pdf

Converts various HTML5 slide decks to PDF
Java
241
star
3

jdoctor

A Java library for designing good error messages
Java
133
star
4

gr8confagenda

Source code for the GR8Conf Agenda Android application
Groovy
118
star
5

includegit-gradle-plugin

A Gradle plugin to include Git repositories
Java
95
star
6

asm-bytecode-intellij

An ASM (http://asm.ow2.org/) plugin for IntelliJ IDEA
Java
69
star
7

grooidshell-example

An example of usage of dynamic classes at runtime using Groovy on Android
Java
45
star
8

groovy-bytecode-ast

A Groovy AST transformation which allows writing the body of a method as bytecode instructions.
Groovy
45
star
9

gradle-buildscan-recipes

A Gradle plugin for Build Scans
Groovy
43
star
10

antlr4-gradle-plugin

Antlr4 plugin for Gradle
Groovy
40
star
11

ast-workshop

Unleashing the power of AST transformations
Shell
38
star
12

jmh-gradle-example

Sample project showcasing the JMH gradle plugin
Java
38
star
13

jlangdetect

A language detection library for the JVM
Java
33
star
14

mrjar-gradle

Example of how to produce a MRJAR with Gradle
Groovy
21
star
15

speakertime

A demo project for Groovy and Android, as seen in Devoxx
Groovy
20
star
16

astro4j

Astronomy libraries for Java
Java
18
star
17

mrjar-gradle-plugin

A multi-release JAR plugin for Gradle
Java
18
star
18

springboot-groovytemplates

A demo app that makes use of Spring Boot, Groovy templates and GORM
Groovy
15
star
19

gradle-presentation-template

A presentation template using Asciidoctor+Reveal.js and Gradle
Kotlin
14
star
20

gradle-6-whats-new

What's new in Gradle 6?
Kotlin
13
star
21

gradle-cf-plugin

Gradle plugin for CloudFoundry
Groovy
13
star
22

gradle-tapi-demo-artifacts

A demonstration of the Gradle Tooling API: inspecting Gradle builds to get some information about them
Java
12
star
23

teamcity-groovy-buildstep

A TeamCity plugin which adds the ability to write a build step using Groovy
JavaScript
10
star
24

openbeans

Automatically exported from code.google.com/p/openbeans
Java
9
star
25

codenarc-idea

Java
9
star
26

blog

My blog
CSS
8
star
27

gradle-wasm-plugin

A POC of writing Gradle tasks using wasm as implementation
Java
7
star
28

micronaut-test-resources-demo

Java
7
star
29

lecharny-challenge

The Lecharny Challenge
Java
7
star
30

gradle-maven-exec

Embedding Maven build in Gradle
Kotlin
6
star
31

graal-simple-httpserver

A simple HTTP server using Kotlin, Groovy and Gradle
Kotlin
6
star
32

version-catalog-poc

Kotlin
5
star
33

grithub

A Groovy API for GitHub Java API
Groovy
5
star
34

robovm-groovy-test

A test project for Groovy on RoboVM
Groovy
4
star
35

spring-groovymarkup

Support classes for using MarkupTemplateEngine from Spring
Java
4
star
36

maven-repository-injection

A POC which demonstrates repository injection with Apache Maven
Java
4
star
37

staticbuilder

Statically compiled markup builder for Groovy
Java
4
star
38

javaone2016-juggling-jigsaw

Groovy
3
star
39

advisories-gradle-plugin

A plugin which scans your dependencies for vulnerabilities looking at GitHub advisories database
Kotlin
3
star
40

groovy-guava

A Groovier API for Google Guava
Groovy
3
star
41

javaone-groovy-dsls

HTML
3
star
42

paseq-gradle-plugin-poc

Proof of concept of paseq plugin for Gradle
Java
3
star
43

poc-gradle-git-demo

Demonstrates generation of a class from Git info
Java
3
star
44

gradle-variant-aware-dependency-resolution

Java
2
star
45

devoxxbe2015-groovy-dsls

HTML
2
star
46

finistjug-fast-builds

HTML
2
star
47

gradlesummit2016-jigsaw-gradle

Java
2
star
48

gradle-compile-avoidance-current-model

Groovy
2
star
49

gradle-repl

Kotlin
2
star
50

kotlin-mpp-demo

Kotlin
2
star
51

s2gx-groovy-dsls

Slides for S2GX 2015 "Building modern DSLs in Groovy"
HTML
2
star
52

bdxjug2015

Talk at BordeauxJUG, May 2015
Groovy
2
star
53

gradle-download-helper

Java
2
star
54

rivieradev-composite-builds

Talk about composite builds at RivieraDev 2017
HTML
2
star
55

benchmark-groovy-gstring

Benchmark for String concatenation in Groovy
Groovy
2
star
56

gr8conf2016-intro-software-model

Introduction to the new Java software model in Gradle
Groovy
2
star
57

gradle-javac-dependencies-plugin

Experimental javac plugin
Java
2
star
58

jroller-export

Exports from JRoller.com to JBake compatible format
Shell
2
star
59

micronaut-license-report

An aggregating project to generate a license report
Kotlin
1
star
60

s2gx-deepdive-groovy-compiler

Slides for S2GX 2015 "Deep dive into the Groovy compiler"
Groovy
1
star
61

micronaut-aot-demo

Java
1
star
62

gradle-dependencies-dump

Playground for dumping gradle dependencies
Java
1
star
63

s2gx-2013

SpringOne2GX 2013 slideware
JavaScript
1
star
64

gr8conf2016-deepdive-groovy-compiler

Deep dive into the Groovy compiler - GR8Conf Europe 2016
Groovy
1
star
65

devoxxfr2013

Slides and source code for Devoxx France 2013 conferences
Shell
1
star
66

ggx2013

Slides for my Groovy & Grails eXchange 2013 talk
JavaScript
1
star
67

CodeStory

Concours CodeStory
Groovy
1
star
68

webinar-dep-mgmt-part-2

Kotlin
1
star
69

micronaut-uber-build

Java
1
star
70

gr8conf2016-variant-aware-dep-mgmt

Slides for "Variant aware dependency management with Gradle"
HTML
1
star
71

talks

Slides for various talks
JavaScript
1
star
72

gradle-global-config-consistency-plugin

Kotlin
1
star
73

virtualjug-fast-builds

HTML
1
star
74

paris-android-ug-fast-builds

Slides for my Paris Android User Group talk
HTML
1
star
75

micronaut-svelte-demo

Java
1
star
76

javaone-2017-max-incremental

Slides for my JavaOne 2017 talk : minutes to seconds - maximizing incrementality
HTML
1
star
77

javaone-2017-jigsaw

Slides for my JavaOne 2017 talk : building and testing Java 9 applications with Gradle
HTML
1
star
78

groovy-script-extension-example

Java
1
star
79

sphero-playground

Go
1
star