Is it possible to override generated buildscript snippet for plugin?

Hello all!

Plugin i’m publishing (SoapUI runners) is required smartbear maven repository. I added this kind of info in plugin github repo README, but it’s not obvious for users found that plugin via Grade portal and I’d like to show right buildscript snipped with that additional repository included.

Few example:
Gradle portal shows buildscript snippet:

buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
    }
  }
  dependencies {
    classpath "gradle.plugin.io.github.daggerok:soapui-runner:4.6.1"
  }
}

apply plugin: "io.github.daggerok.soapui-runner"

while right one must be

buildscript {
  repositories {
    maven { url "https://plugins.gradle.org/m2/" }
    maven { url "http://smartbearsoftware.com/repository/maven2/" }
  }
  dependencies {
    classpath "gradle.plugin.io.github.daggerok:soapui-runner:4.6.1"
  }
}

apply plugin: "io.github.daggerok.soapui-runner"

or for gradle >= 2.1, it showing snippet:

plugins {
  id "io.github.daggerok.soapui-runner" version "4.6.1"
}

when correct for that plugin looks like so:

buildscript {
  repositories {
    maven { url "https://plugins.gradle.org/m2/" }
    maven { url "http://smartbearsoftware.com/repository/maven2/" }
  }
}

plugins {
  id "io.github.daggerok.soapui-runner" version "4.6.1"
}

Or maybe you know how can I programmatically generate project buildscript and add here needed repository in runtime as soon plugin users applied it in their build.gradle? (but seems like it’s wrong place for that discussion…)

Thanks in any advice!


Regards,
Max

I received answer from Tim Yates regarding plugin-publish functionality:

Currently, no :slightly_frowning_face:

I like the way you’ve done it with the example build script high up in your readme documentation
That’s how I would do it

what about adding repository to the buildscript from a plugin in runtime? Is it possible?

Yes, this sort of thing isn’t possible.

I think you may want to detangle your plugin from that dependency. It doesn’t really make sense to load the smartbear dependencies into the plugin and then use them directly because you’ll run into conflicts with the Gradle runtime or other plugins. This limits what your plugin can do and how people can use it.

I’d take a look at the Worker API that was introduced in 4.0 and formally announced in 4.1. This is what the Android plugin uses to safely do things without a lot of work (juggling classloaders or separate processes).

I don’t think this is very different from what you’re already doing. You would need to introduce a new configuration (e.g., soapui) and default to a particular version of the smartbear library. Your plugin could add the smartbear repos as a regular project repository. Then you would use the soapui configuration as the classpath of your worker. There are several samples and a user guide section describing how to use the API.

I think this would give you a few benefits:

  • You won’t have to deal with classpath conflicts between other plugins and the soap runner
  • You won’t have to run things within the Gradle process and force users to run with a larger daemon (if that’s a problem)
  • You’ll get worker daemon reuse and safe parallelization
  • The plugin can be made to support different versions of SoapUI (if that’s useful) without requiring the Gradle plugin to be released

Thanks for information

…interesting, seems like I need to learn Worker API first…

so idea is:

  1. in my plugin I’m creating configuration, such as soapui
  2. on client side in build.gradle i’m using that configuration:

not:

dependencies {
  classpath 'my-plugin-fqdn'
}

but:

dependencies {
  soapui 'my-plugin-fqdn'
}

Right? Or I missed something?

Thanks


BR, Max

Yeah, that’s close.

People would continue to apply your plugin as usual, but your plugin would do a few things for them:

  1. Add smartbear repo
  2. Add a new configuration (soapui)
  3. If no dependencies are defined for soapui, provide a default version.

I put together a sample here that does these things for a simple task (it extracts the version of the findbugs library added to the worker configuration): https://github.com/big-guy/plugin-worker-api

Thanks a lot!


Regards,
Max

Even if you start adding the SmartBear repository by default, please consider providing an easy way to disable the feature for corporate users.

In many corporate environments adding a repository other than the internal aggregate repository is incorrect. Those users would instead add the SmartBear repository as an additional proxied repository on their internal repository or host just the required artifacts. The plugin becomes much harder to use for these types of users if code has to be added to circumvent the plugin trying to be helpful.

@jjustinic I decide not forcing any repositories at all

Seems like adding repository via plugin is to late.
Plugin execution is happens after buildsctip.repository evaluated.
Adding repository via project.repositorues {} is not enough for plugins (or I’m not experienced enough to handle it…)

Any way, I added needed information to README, so users will available to and responsible for handling all jar-hell or artifactory compatibility issues…

There is no relation to buildscript {} if you do it like Sterling showed. The point is to not load the dependency when your plugin is loaded, but only when a task is run, in a different worker.

@st_oehme, for test I tried add gradle portal repository like from worker example

In apply method:

project.repositories.add {
maven { ‘repo-uri’ }
}

but on clien side it still wasn’t able to resolve dependency until I add same repo in buildscript dependencies classpath

I will try play more little bit later