t3chb0t
t3chb0t

Reputation: 18646

Apply local jar-plugin without using maven

I'd like to load my custom plugin from a local jar. The jar file compiles fine and when I check it, the manifest and the plugin class are there.

gradlePlugin {
    plugins {
        create("asdf") { // <-- I really call it "asdf" in the kts script
            id = "asdf"
            implementationClass = "pluginTest.TestPlugin"
            version = "1.4.0"
        }
    }
}

The plugin doesn't do anything useful yet as it should be a proof-of-concept to make sure it actually works at all:

class TestPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        println("Hallo TestPlugin!")
    }
}

I then try to use it like this in another project:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath(files("..\\..\\path\\to\\pluginTest.jar"))
    }
}

plugins {
    id("asdf") version "1.4.0"
}

but it keeps telling me that:

Plugin [id: 'asdf', version: '1.4.0'] was not found in any of the following sources:

What am I missing here? I use Gradle v6.5.

Upvotes: 2

Views: 2206

Answers (3)

18446744073709551615
18446744073709551615

Reputation: 16832

This answer https://stackoverflow.com/a/35472676/755804 also answers this question, and provides an example project that still works in 2024, provided that you rewrite or comment out the list task.

Basically, in 2024 and with Gradle 8.9, the minimal "magic spell" is:

build.gradle:

buildscript {
    dependencies{
        // relative from the directory containing this build.gradle
        classpath fileTree(dir:'../../../../path-to-plugin-project/build/libs', include: ['*.jar'])
    }
}
plugins {
    id 'application'
}
// important: the old way, "apply plugin: ..." rather than "plugins { id ... }"
apply plugin: 'io.github.myname.myplugin'
repositories {
    jcenter()
}

Note that the plugin version is not specified, it will work even if the version changes.

Upvotes: 0

t3chb0t
t3chb0t

Reputation: 18646

With @BjørnVester's answer I figured it out!

You need to put the buildscript in settings.gradle.kts as it doesn't get executed in the build.gradle.kts even when placed before plugins.

buildscript {
    repositories {
        flatDir {
            dirs("..\\reusable-kotlin\\build\\libs") // <-- folder with jars
        }
    }
    dependencies {        
        classpath("com.hedev.kotlin:reusable-kotlin:1.4.0")
    }
}

But there's a catch! You must use the file-name of the jar in the classpath's name identifier that goes like this:

group:file-name:version

The file gradle will look for will be file-name-version.jar or file-name.jar which you'll see in the error message if you make a mistake (I added the _ on purpose to trigger the error):

Could not resolve all artifacts for configuration 'classpath'.
Could not find com.hedev.kotlin:reusable-kotlin_:1.4.0. Searched in the following locations:
- file:/C:/some/path/reusable-kotlin/build/libs/reusable-kotlin_-1.4.0.jar
- file:/C:/some/path/reusable-kotlin/build/libs/reusable-kotlin_.jar

In order for this to work I also had to add the group property to the plugin itself:

gradlePlugin {
    plugins {
        create("asdf") {
            id = "asdf"
            implementationClass = "com.hedev.kotlin.gradle.TestPlugin"
            version = "1.4.0"
            group = "com.hedev.kotlin"
        }
    }
}

Finally you can apply it in build.gradle.kts with (no version here):

plugins {
    id("asdf")
}

Upvotes: 3

Bj&#248;rn Vester
Bj&#248;rn Vester

Reputation: 7600

When you have the plugin jar on the classpath, you can't have a version number in the plugin application. I guess this is because you can't have multiple jars with different versions on the classpath in the first place, so specifying a version here doesn't make any sense (except perhaps to validate that you are using the correct one). This won't fix the problem, but it is a start.

To be honest, I don't know why your approach still won't work. The buildscript block is supposed to set up dependencies for that particular script, and that should make the plugin visible to it. It doesn't for some reason.

Perhaps this is a bug or perhaps this is just an undocumented limitation on the use of the plugin {} block. Maybe you could ask over at the Gradle forums or create an issue for it. However, there are workarounds that don't involve publishing to a (local) Maven repository, which I agree can be a bit annoying.

If you use "apply from" instead of "plugins {}", it works. For some reason, the former can see the buildscript classpath whereas the latter can't:

// build.gradle (Groovy DSL)
buildscript {
    dependencies {
        classpath(files("..\\..\\path\\to\\pluginTest.jar"))
    }
}

apply from: "asdf"

Alternatively, move the buildscript plugin from the build.gradle file to the settings.gradle file. This makes is available to the entire build classpath and will make it work with the plugin block:

// settings.gradle (Groovy DSL):
buildscript {
    dependencies {
        classpath(files("..\\..\\path\\to\\pluginTest.jar"))
    }
}

// build.gradle (Groovy DSL)
plugins {
    id("asdf")
}

Lastly, just in case you haven't considered it already, you may be able to add the plugin as a composite build. This will create a source dependency to the plugin and has the advantage that transitive dependencies will be carried over (the ones you put in the plugin's own dependency block) and that it will be built automatically if not up-to-date. I use this approach for integration testing my plugins and also sometimes to apply them to my other real projects to test them in a bigger setting before publishing new versions.

Do that with either:

// settings.gradle (Groovy DSL):
includeBuild("..\\..\\path\\to\\plugin")

// build.gradle (Groovy DSL):
plugins {
    id("asdf")
}

Or without hard-coding it in the build (so you can dynamically switch between local and published versions):

// build.gradle (Groovy DSL):
plugins {
    id("asdf") version "1.4.0" // Version is optional (will be ignored when the command line switch below)
}

// Run with:
./gradlew --include-build "..\\..\\path\\to\\plugin" build

Upvotes: 2

Related Questions