I'm trying to get test coverage report of our Android application module and executing the testVariantBuildTypeUnitTest task.
Although all tests are passed, TEST-classNameTest.xml file contains error message below. This error is only given for methods contain calls Java from Kotlin. Is there any solution for this issue ?
**Caused by: java.lang.IllegalStateException: Cannot process instrumented class... Please supply original non-instrumented classes.
at org.jacoco.agent.rt.internal_f3994fa.core.internal.instr.InstrSupport.assertNotInstrumented(InstrSupport.java:238)
at org.jacoco.agent.rt.internal_f3994fa.core.internal.instr.ClassInstrumenter.visitField(ClassInstrumenter.java:56)
at org.jacoco.agent.rt.internal_f3994fa.asm.ClassVisitor.visitField(ClassVisitor.java:339)
at org.jacoco.agent.rt.internal_f3994fa.asm.ClassReader.readField(ClassReader.java:1111)
at org.jacoco.agent.rt.internal_f3994fa.asm.ClassReader.accept(ClassReader.java:713)
at org.jacoco.agent.rt.internal_f3994fa.asm.ClassReader.accept(ClassReader.java:401)
at org.jacoco.agent.rt.internal_f3994fa.core.instr.Instrumenter.instrument(Instrumenter.java:90)
at org.jacoco.agent.rt.internal_f3994fa.core.instr.Instrumenter.instrument(Instrumenter.java:108)
We have multimodule android project, because of this we're using this custom Jacoco task to get coverage report:
project.afterEvaluate {
(android.hasProperty('applicationVariants')
? android.'applicationVariants'
: android.'libraryVariants')
.all { variant ->
def variantName = variant.name
def unitTestTask = "test${variantName.capitalize()}UnitTest"
def jacocoReportName = unitTestTask + project.name
tasks.create(name: jacocoReportName, type: JacocoReport, dependsOn: [
"$unitTestTask"
]) {
group = "Reporting"
description = "Generate Jacoco coverage reports for the ${variantName.capitalize()} build"
reports {
html.enabled = true
xml.enabled = true
}
def fileFilter = [
// data binding
'android/databinding/**/*.class',
'**/android/databinding/*Binding.class',
'**/android/databinding/*',
'**/androidx/databinding/*',
'**/databinding',
'**/BR.*',
// android
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Test*.*'
]
def javaClasses = fileTree(dir: variant.javaCompileProvider.get().destinationDir,
excludes: fileFilter)
def kotlinClasses = fileTree(dir: "${buildDir}/tmp/kotlin-classes/${variantName}",
excludes: fileFilter)
classDirectories.setFrom(files([
javaClasses,
kotlinClasses
]))
def variantSourceSets = variant.sourceSets.java.srcDirs.collect { it.path }.flatten()
sourceDirectories.setFrom(project.files(variantSourceSets))
if (isAndroidLibrary(project)) {
executionData(files([
"${projectDir}/jacoco.exec"
]))
}else{
executionData(files([
"$project.buildDir/jacoco/${project.name}.exec"
]))
}
}
}
}
Regards,
Solution
The problem most likely lies in your module level build.gradle file. You need to remove testCoverageEnabled or set it to false.
android {
...
buildTypes {
release {
minifyEnabled true
}
debug {
// testCoverageEnabled true
minifyEnabled false
}
}
Explanation and References
Firstly I've been struggling with unit test coverage on android with JaCoCo for years and repeatedly encountered the issues multiple times as the AGP (Android Gradle Plugin) team enhanced the AGP (e.g. Similar issue) therefore this solution is subject to change in future releases of the AGP.
Come the release of AGP 4.1 the AGP team changed the way the plugin deals with unit tests. I raised an enter link description here issue with the AGP team and they explained that the plugin (AGP 4.1+) does it's own form of instrumentation to get the coverage which is undoubtedly incompatible with JaCoCo. It was in this issue where the solution was highlighted to me.
Note 1: This issue is not documented in the DSL documentation!
Note 2: It should also be noted that as of when I wrote this AGP 7 is in development where the same issue occurs.
Considerations
This solution will cause a problem generating coverage for instrumented tests as the AGP generates coverage for instrumented tests (in the form of a .ec file) meaning to get instrumented test coverage you must have testCoverageEnabled true.
As a workaround you could:
Put your unit tests in the release build variant
Put your instrumented tests in the debug build variant.
It's still possible to combine the coverage into one report: for example:
task jacocoCombinedUnitTestAndroidTestReport(type: JacocoReport) {
group = "Reporting"
reports {
xml.enabled = true
html.enabled = true
}
def mainSrc = "$project.projectDir/src/main/java"
def releaseKotlinClasses = fileTree(dir: "${buildDir}/tmp/kotlin-classes/release", excludes:["com/example/ui**"])
def debugKotlinClasses = fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug/com/example/ui/")
def releaseJavaClasses = fileTree(dir: "${buildDir}/intermediates/javac/release", excludes: ["com/example/ui**"])
def debugJavaClasses = fileTree(dir: "${buildDir}/intermediates/javac/debug/com/example/ui/" )
def mainClasses = releaseKotlinClasses + debugKotlinClasses
def javaClasses = releaseJavaClasses + debugJavaClasses
sourceDirectories.from = files([mainSrc])
classDirectories.from = files([mainClasses, javaClasses])
executionData.from = fileTree(dir: buildDir, include: ["jacoco/testReleaseUnitTest.exec",
"outputs/code_coverage/debugAndroidTest/connected/**.ec"])
}
This assumes you have any UI code in a ui directory.
You include all release classes excluding the ui directory
You only include your ui debug classes.
Please note this is only valid as of when this answer was written and hopefully Google will fix the issue in the future.
Related
I've got a Gradle project which uses a Java version specified with the toolchain API:
val minimumJava = JavaLanguageVersion.of(8)
val maximumJava = JavaLanguageVersion.of(16)
java {
toolchain {
languageVersion.set(minimumJava)
vendor.set(JvmVendorSpec.ADOPTOPENJDK)
}
}
I would like to be able to compile with the minimum supported Java version, then run the tests with all the JDKs the project supports.
I tried the following, but apparently only the original tests get executed, all other tests don't, even though the required JDKs get correctly downloaded and set up:
for (javaVersion in JavaLanguageVersion.of(minimumJava.asInt() + 1)..maximumJava) {
val base = tasks.test.get()
val testTask = tasks.register<Test>("testUnderJava${javaVersion.asInt()}") {
javaLauncher.set(
javaToolchains.launcherFor {
languageVersion.set(javaVersion)
}
)
classpath = base.classpath
testClassesDirs = base.testClassesDirs
isScanForTestClasses = true
}
tasks.test.configure { finalizedBy(testTask) }
}
Here is a run in a dumb terminal:
❯ TERM=dumb ./gradlew test testUnderJava10 --rerun-tasks --scan
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on
<<<SNIP>>>
> Task :testClasses
> Task :test
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on
Gradle Test Executor 4 STANDARD_OUT
~~~ Kotest Configuration ~~~
-> Parallelization factor: 1
-> Concurrent specs: null
-> Global concurrent tests: 1
-> Dispatcher affinity: true
-> Default test timeout: 600000ms
-> Default test order: Sequential
-> Default isolation mode: SingleInstance
-> Global soft assertions: false
-> Write spec failure file: false
-> Fail on ignored tests: false
-> Spec execution order: SpecExecutionOrder
-> Remove test name whitespace: false
-> Append tags to test names: false
-> Extensions
- io.kotest.engine.extensions.SystemPropertyTagExtension
- io.kotest.core.extensions.RuntimeTagExtension
- io.kotest.engine.extensions.RuntimeTagExpressionExtension
org.danilopianini.template.test.Tests > A greeting should get printed STARTED
org.danilopianini.template.test.Tests > A greeting should get printed STANDARD_OUT
[:hello=SUCCESS]
> Task :hello
Hello from Danilo Pianini
BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed
org.danilopianini.template.test.Tests > A greeting should get printed PASSED
<<<Other tests have no output!>>>
> Task :testUnderJava9
> Task :testUnderJava8
> Task :testUnderJava16
> Task :testUnderJava15
> Task :testUnderJava14
> Task :testUnderJava13
> Task :testUnderJava12
> Task :testUnderJava11
> Task :testUnderJava10
BUILD SUCCESSFUL in 23s
36 actionable tasks: 36 executed
<<<SNIP>>>
From the build scan, it appears that tests are not executed but those with JDK8. I'm puzzled, the docs say that this should be straightforward:
tasks.register<Test>("testsOn14") {
javaLauncher.set(javaToolchains.launcherFor {
languageVersion.set(JavaLanguageVersion.of(14))
})
}
I think I worked out the root cause of the issues I was experiencing, I'm posting the solution in case someone else runs into similar issues.
I had the following tests configuration:
tasks.test {
useJUnitPlatform()
testLogging {
showStandardStreams = true
showCauses = true
showStackTraces = true
events(*org.gradle.api.tasks.testing.logging.TestLogEvent.values())
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
}
Which was instructing the task called test to useJunitPlatform(). This setting does not get automatically propagated to all subsequent Test tasks (of course). So, in this case, the solution is simply to use instead:
tasks.withType<Test> {
// Same configuration as above
}
Update 2022-03-16
I decided to create a multi-JVM testing plugin for Gradle, so that all the test tasks get created and much less boilerplate is required across projects.
Update 2023-01-17
Gradle recommends using the task configuration avoidance API.
tasks.withType<Test>().configureEach {
// Same configuration as above
}
In python, using Coverage.py we are able to get line information about code coverage on the command line using coverage report --show-missing. This showed what lines of each file weren't being covered.
Using gradle plugins, the best output I can get is:
- Class Coverage: 10%
- Method Coverage: 3.2%
- Branch Coverage: 100%
- Line Coverage: 1.2%
- Instruction Coverage: 1.1%
- Complexity Coverage: 3.2%
However as this does not give line information, you may as well just look at html output.
My test.gradle file:
buildscript {
repositories {
mavenCentral()
}
}
plugins {
id 'application'
id 'jacoco'
id 'com.github.ksoichiro.console.reporter' version '0.6.2'
id 'org.barfuin.gradle.jacocolog' version '1.2.4'
}
dependencies {
implementation files('lib/json.jar')
implementation files('lib/junit-platform-console-standalone-1.7.0-M1.jar')
implementation files('lib/jsonassert-1.2.3.jar')
}
test {
useJUnitPlatform()
finalizedBy jacocoTestReport // report is always generated after tests run
ignoreFailures = true
}
test.outputs.upToDateWhen {false}
jacocoTestReport {
dependsOn test // tests are required to run before generating the report
}
repositories {
mavenCentral()
}
group 'unsw.blackout'
apply plugin: 'java'
sourceSets.test.java.srcDirs = ['src']
sourceSets.test.java.excludes = ['degree/*']
sourceSets.main.java.srcDirs = ['src']
sourceSets.main.java.excludes = ['degree/*']
Is there an equivalence for gradle?
I want to code my own minecraft mod and i am following a youtube tutorial.
i did everything right, but in IntelliJ IDEA in the build.gradle file it says "Cannot resolve symbol 'Date'"
here is the full code of the build.gradle file:
buildscript {
repositories {
maven { url = 'https://files.minecraftforge.net/maven' }
jcenter()
mavenCentral()
}
dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '4.1.+', changing: true
}
}
apply plugin: 'net.minecraftforge.gradle'
// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
apply plugin: 'eclipse'
apply plugin: 'maven-publish'
version = '1.0'
group = 'netjackboi03.forestportal' // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = 'forestportal'
java.toolchain.languageVersion = JavaLanguageVersion.of(8) // Mojang ships Java 8 to end users, so your mod should target Java 8.
println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
minecraft {
// The mappings can be changed at any time, and must be in the following format.
// Channel: Version:
// snapshot YYYYMMDD Snapshot are built nightly.
// stable # Stables are built at the discretion of the MCP team.
// official MCVersion Official field/method names from Mojang mapping files
//
// You must be aware of the Mojang license when using the 'official' mappings.
// See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md
//
// Use non-default mappings at your own risk. they may not always work.
// Simply re-run your setup task after changing the mappings to update your workspace.
mappings channel: 'official', version: '1.16.5'
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
// accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
// Default run configurations.
// These can be tweaked, removed, or duplicated as needed.
runs {
client {
workingDirectory project.file('run')
// Recommended logging data for a userdev environment
// The markers can be changed as needed.
// "SCAN": For mods scan.
// "REGISTRIES": For firing of registry events.
// "REGISTRYDUMP": For getting the contents of all registries.
property 'forge.logging.markers', 'REGISTRIES'
// Recommended logging level for the console
// You can set various levels here.
// Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
property 'forge.logging.console.level', 'debug'
mods {
forestportal {
source sourceSets.main
}
}
}
server {
workingDirectory project.file('run')
// Recommended logging data for a userdev environment
// The markers can be changed as needed.
// "SCAN": For mods scan.
// "REGISTRIES": For firing of registry events.
// "REGISTRYDUMP": For getting the contents of all registries.
property 'forge.logging.markers', 'REGISTRIES'
// Recommended logging level for the console
// You can set various levels here.
// Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
property 'forge.logging.console.level', 'debug'
mods {
forestportal {
source sourceSets.main
}
}
}
data {
workingDirectory project.file('run')
// Recommended logging data for a userdev environment
// The markers can be changed as needed.
// "SCAN": For mods scan.
// "REGISTRIES": For firing of registry events.
// "REGISTRYDUMP": For getting the contents of all registries.
property 'forge.logging.markers', 'REGISTRIES'
// Recommended logging level for the console
// You can set various levels here.
// Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
property 'forge.logging.console.level', 'debug'
// Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
args '--mod', 'forestportal', '--all',
'--existing', file('src/main/resources').toString(),
'--existing', file('src/generated/resources').toString(),
'--output', file('src/generated/resources/')
mods {
forestportal {
source sourceSets.main
}
}
}
}
}
// Include resources generated by data generators.
sourceSets.main.resources { srcDir 'src/generated/resources' }
dependencies {
// Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed
// that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied.
// The userdev artifact is a special name and will get all sorts of transformations applied to it.
minecraft 'net.minecraftforge:forge:1.16.5-36.0.58'
// You may put jars on which you depend on in ./libs or you may define them like so..
// compile "some.group:artifact:version:classifier"
// compile "some.group:artifact:version"
// Real examples
// compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
// compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
// The 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
// provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
// These dependencies get remapped to your current MCP mappings
// deobf 'com.mod-buildcraft:buildcraft:6.0.8:dev'
// For more info...
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
// http://www.gradle.org/docs/current/userguide/dependency_management.html
}
// Example for how to get properties into the manifest for reading by the runtime..
jar {
manifest {
attributes([
"Specification-Title": "forestportal",
"Specification-Vendor": "examplemodsareus",
"Specification-Version": "1", // We are version 1 of ourselves
"Implementation-Title": project.name,
"Implementation-Version": "${version}",
"Implementation-Vendor" :"examplemodsareus",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
])
}
}
// Example configuration to allow publishing using the maven-publish task
// This is the preferred method to reobfuscate your jar file
jar.finalizedBy('reobfJar')
// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing
//publish.dependsOn('reobfJar')
publishing {
publications {
mavenJava(MavenPublication) {
artifact jar
}
}
repositories {
maven {
url "file:///${project.projectDir}/mcmodsrepo"
}
}
}
The problem lies in this line of code:
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
I don't know if this is significant to run the mod, but i wanted to make sure it isn't.
Thanks for your help :)
I need to say that I don't know. On 1.16.4 it works perfectly, but I have no idea why this don't work on 1.16.5. Maybe try to delete this line and then see if everything works well without this line.
I am trying to add the following task so that I can get some coverage data in my java + kotlin project (for what it is worth, this is a gradle project)... but I get the following error :
"Cannot add task ':jacocoTestReport' as a task with that name already exists"
Here is the actual task I am trying to add :
task jacocoTestReport(type: JacocoReport, dependsOn: "testDebugUnitTest") {
group = "Reporting"
description = "Generate Jacoco coverage reports for Debug build"
reports {
xml.enabled = true
html.enabled = true
}
// what to exclude from coverage report
// UI, "noise", generated classes, platform classes, etc.
def excludes = [
'**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Test*.*',
'android/**/*.*',
'**/*Fragment.*',
'**/*Activity.*'
]
// generated classes
classDirectories = fileTree(
dir: "$buildDir/intermediates/classes/debug",
excludes: excludes
) + fileTree(
dir: "$buildDir/tmp/kotlin-classes/debug",
excludes: excludes
)
// sources
sourceDirectories = files([
android.sourceSets.main.java.srcDirs,
"src/main/kotlin"
])
executionData = files("$buildDir/jacoco/testDebugUnitTest.exec")
}
Now, the issue I am confused about here, is that I can't find another class of this name anywhere... so perhaps there is something funky going on? I have tried googling this, but haven't really been able to find anything which truly helps me solve the problem.
All help greatly appreciated. I realize this is not a java or kotlin specific problem - but since it is a joint java + kotlin project, I thought I would tag both in this question, in case there is some nuanced issue that somebody else has seen.
Assuming you're already applying the Jacoco Gradle plugin, then yes, it already defines a task called jacocoTestReport, hence the error.
All you need to do is define your specific settings as per the documentation https://docs.gradle.org/current/userguide/jacoco_plugin.html#sec:jacoco_report_configuration
an example is below:
jacocoTestReport {
dependsOn "testDebugUnitTest"
reports {
xml.enabled = true
html.enabled = true
}
}
Most of the other configuration items you've listed belong in the 'jacoco' configuration block.
https://docs.gradle.org/current/userguide/jacoco_plugin.html#sec:jacoco_specific_task_configuration
I am still trying to get my gradle script work, I have expolered all logs and it seems that there are some classes are missing. Here is message.
org.gradle.api.GradleScriptException: A problem occurred evaluating project ':horizontalrecyclerview'.
Caused by: java.lang.NoClassDefFoundError: org/gradle/api/publication/maven/internal/DefaultMavenFactory
at org.gradle.api.plugins.AndroidMavenPlugin.apply(AndroidMavenPlugin.java:88)
at org.gradle.api.plugins.AndroidMavenPlugin.apply(AndroidMavenPlugin.java:57)
at org.gradle.api.internal.plugins.ImperativeOnlyPluginApplicator.applyImperative(Imper
Caused by: java.lang.ClassNotFoundException: org.gradle.api.publication.maven.internal.DefaultMavenFactory
... 51 more
Here is my build.gradle.
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'
version = "1.0.0"
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
minSdkVersion 8
targetSdkVersion 21
versionCode 1
versionName "1.0.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
def siteUrl = 'https://github.com/CROSP/AndroidHorizontalRecyclerView' // Homepage URL of the library
def gitUrl = 'https://github.com/CROSP/AndroidHorizontalRecyclerView.git' // Git repository URL
group = "com.github.crosp.horizontalrecyclerview" // Maven Group ID for the artifact
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'org.jsoup:jsoup:1.8.1'
compile 'com.android.support:appcompat-v7:22.1.1'
compile 'com.android.support:recyclerview-v7:21.0.3'
}
install {
repositories.mavenInstaller {
// This generates POM.xml with proper parameters
pom {
project {
packaging 'aar'
// Add your description here
name 'Android Horizontal Recycler View with Headerr'
description = 'Android Horizontal Recycler View with Header project for displaying horizontal list on Android '
url siteUrl
// Set your license
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id 'crosp'
name 'Alexandr Crospenko'
email 'crosp#xakep.ru'
}
}
scm {
connection gitUrl
developerConnection gitUrl
url siteUrl
}
}
}
}
}
task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}
task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives javadocJar
archives sourcesJar
}
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
// https://github.com/bintray/gradle-bintray-plugin
bintray {
user = properties.getProperty("bintray.user")
key = properties.getProperty("bintray.apikey")
configurations = ['archives']
pkg {
repo = "maven"
// it is the name that appears in bintray when logged
name = "crosp"
websiteUrl = siteUrl
vcsUrl = gitUrl
licenses = ["Apache-2.0"]
publish = true
version {
gpg {
sign = true //Determines whether to GPG sign the files. The default is false
passphrase = properties.getProperty("bintray.gpg.password") //Optional. The passphrase for GPG signing'
}
// mavenCentralSync {
// sync = true //Optional (true by default). Determines whether to sync the version to Maven Central.
// user = properties.getProperty("bintray.oss.user") //OSS user token
// password = properties.getProperty("bintray.oss.password") //OSS user password
// close = '1' //Optional property. By default the staging repository is closed and artifacts are released to Maven Central. You can optionally turn this behaviour off (by puting 0 as value) and release the version manually.
// }
}
}
}
Maybe someone already had such problem or know the way to solve it ? Please help, because I cannot get it work whole day already.
Thx in advance.
I am doing the same thing (upload my aar to bintray) and I have the same problem.
I am aware that it is occurred in gradle library, so I change my gradle verion from 2.4.0 to 2.2.1 by this way
File -> Project Structure (or trigger hotkey command + ;) -> click the Project in the left list in the dialog -> input 2.2.1 in the Gradle textedit box.
I solve this error by this way.Look for the note part in file README.md.
Hope this can help you.
ps:If you want to use gradle 2.4.0, you should config android-maven-plugin version to 1.3 in classpath in the project root build.gradle as :
com.github.dcendents:android-maven-gradle-plugin:1.3