PluginServiceRegistry are not loaded with test-kit

Hi,

I’m currently writing a custom gradle plugin and stumbled over the new test-kit. It looks exactly what I’m looking for to create my integration tests. Easy and simple to use. But there is a problem with this tool-kit when META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry files are contained in the custom plugin, because they are not considered at all.

The reason is (or at least I think that it is), that on loading of all Registries with the org.gradle.internal.service.ServiceLocator#getAll method, my custom META-INF/... file is not found because the registered ClassLoaders used for lookup, all have parent of the type org.gradle.internal.classloader.FilteringClassLoader and the method getResources(...) of it prevents that the classpath with my file is looked up (actually it is prevented that the super.getResources(...) method is called which would than find my file).

From my point of view, one solution could be to allow resource names with the name org.gradle.internal.service.scopes.PluginServiceRegistry.

best regards
Guenther

Can you explain why you need to use these internal classes from your plugin? The service registry is an internal mechanism and shouldn’t be used by a custom plugin.

HI,

I didn’t know that the Registry is not intended to be used for custom plugins. I just want to write a plugin which allows fallback dependencies (when a dependency can not be resolved, use it’s fallback) and the gradle file should looks like this:

... dependencies { compile ('some-dependency') { fallback('some-fallback-dependency') } }

But to allow this syntax, the dependency classes needs to be wrapped, else the fallback(...) can’t be resolved.

Kind Regards
Guenther

Thanks for clarifying. This functionality would require reaching into the internal classes as it is not exposed as such through the public API.

Before we tackle the situation on a technical level, can you describe the need to such functionality? Maybe we can use an existing, public API to solve your use case. Under what condition is a dependency not resolved? Does this happen because of network issues?

Hi,

If there is something available in the public API I would be more than happy to use it.

So here is my situation:
We have commons-projects and business-projects in two different git repositories. The business-code references the commons-libraries.
Now, there is the situation, that for new requirements, business- and commons-code-changes are needed but should be released together.

Of course we do the development with feature branches. In that case, we would have the following branches int the repos:

  • Commons-Repo-branches: feature1, master
  • Business-Repo-branches: feature1, master

The Jar-libs of the commons-projects are always uploaded to Artifactory with the branch name postfixed to the module name (e.g. commons-feature1-13.4.3.jar). The business code than uses the latest version of the commons-feature1:+. But the problem now is, that such a feature branch is not always created for the commons-repo. No branch than means no artifacts with our expected naming. In that case, the dependency to commons in the business code should just fallback to the library created from the master branch which than is the correct one.

Hope this helps you to get the idea what my problem is.

best regards
guenther

If I’d have a choice then I’d change the workflow you have in place right now. Instead of publishing from a feature branch, I’d probably create a new branch called dev. I’d do that for two reasons:

  1. Publishing from every feature branch will lead to many, many branches over time and causes additional complexity in your workflow.
  2. When a feature is ready, then it would need to be merged into the dev branch.
  3. The dev branch of commons and business would always be released together. Developers need to make sure that they are compatible.

If I am understanding your workflow correctly, this change would avoid the need for the fallback method.

If I’d try to solve this technically, I’d do the following:

Write a custom plugin that adds a new extra method to the DependencyHandler. As the first parameter pass in the original coordinates, as the second parameter provide the fallback coordinates. The method definition could look as such:

dependencies {
    ext.fallback = { String originalCoordinates, String fallbackCoordinates ->
        // implementation
    }
}

The usage would look like that:

dependencies {
    compile fallback('com.company:commons-feature1:13.4.3', 'com.company:commons:13.4.3')
}

In the actual implementation of the fallback method I’d make HTTP calls to the Artifactory API that tells you whether an artifact exists or not. If it does exist, simply use the original coordinates. If it doesn’t exist, then use the fallback coordinates. A dependency with one of these coordinates can be created via dependencies.create('com.company:commons-feature1:13.4.3').

Hi,

Thanks a lot for this advise. I know that we have to change something in our workflow, and we will. But this won’t happen over night. For the remaining time, your technical solution sounds perfect to me!

best regards
Guenther