This message was deleted.
# community-support
s
This message was deleted.
v
You should not use
mavenLocal
if possible or at most with using a repository content filter, because
mavenLocal
is broken by design. Better use a composite build. To get the "as close as possible to the experience as simply writing a
build.gradle
file" write your convention plugins as precompiled script plugins as documented at https://docs.gradle.org/current/userguide/custom_plugins.html#sec:precompiled_plugins
n
Unfortunately this just leaves me with more questions than answers, I'd already read this I've created the minimal sample repos/files above with the hope that someone might be able to suggest a few lines of code which demonstrates it - a Github repo like this is exactly what I would have hoped for from the docs
Composite builds do not seem appropriate as it appears they require the "common" repo to be checked out locally already, which may be out-of-date
I'm curious as to what you mean by "mavenLocal is broken by design" - wonder if that contributes to any of my problems so far.
v
I've created the minimal sample repos/files above with the hope that someone might be able to suggest a few lines of code which demonstrates it
Those repos are not accessible, actually.
a Github repo like this is exactly what I would have hoped for from the docs
https://github.com/jjohannes/idiomatic-gradle might be interesting for you, but it might also be way more complex than you actually need and want.
as it appears they require the "common" repo to be checked out locally already,
Yes, that's correct.
which may be out-of-date
Well actually it is usally the other way around. By requiring to manually publish the dependency to some repository or local repository or
mavenLocal()
, you always have to go to that module, change something, publish it manually and then use the new version. With a composite build you can just change something in
common
and run the consumer build which will automatically build and use the dependency. Both have their pros and cons liek always of course, but usually a composite build is much more convenient to work with, at least while developing changes.
I'm curious as to what you mean by "mavenLocal is broken by design" - wonder if that contributes to any of my problems so far.
Here are some of the problems documented: https://docs.gradle.org/current/userguide/declaring_repositories.html#sec:case-for-maven-local
n
Silly me, the repos are visible now 🙂
I am fine with a published module, I would have CI in place to publish any changes to a registry upon changes
My proposal for mavenLocal is literally just for simplicity in this PoC
None of those mavenLocal complaints provide any immediate problems for this PoC, it appears
Just to get a sense of complexity, looking at those repos, and (temporarily) using mavenLocal, how long do you think it would take to achieve that functionality? Are we talking ~2 mins? Soul-crushing if so, given the time I've spent on this: but promising still
But yeah, given all of my previous failed experimentation, this is pretty much my last-ditch effort. Nobody in the org has managed to do this, so this is the decider as to whether we can continue to use Gradle, or bow to pressure from others who want to switch it out with an alternative 🤷
A prohibitive limitation of "precompiled script plugins", it seems - it forces you to put the dependency versions in the depending projects (e.g. app1) - I'm looking for that to be completely abstracted away within the common module (not very DRY at all, otherwise)
v
A prohibitive limitation of "precompiled script plugins", it seems - it forces you to put the dependency versions in the depending projects
No, why should it? Believe me, precompiled script plugins is exactly what you want. And yes, it is more like a 2 minute effort. You basically apply the plugin for the DSL you want to use and configure the publishing using
maven-publish
. Then you can write your convention plugins almost like normal build scripts.
n
Well, I've spent hours so far.
Copy code
Invalid plugin request [id: 'com.diffplug.spotless', version: '6.18.0']. Plugin requests from precompiled scripts must not include a version number. Please remove the version from the offending request and make sure the module containing the requested plugin 'com.diffplug.spotless' is an implementation dependency
I got it working by specifying the dependency in the main project referencing the buildSrc as a plugin - which would lead me to think the same would be needed in a multi-repo setup.
v
That is one of the "*almost* like normal build scripts" points. In the precompiled script plugin you use it without version. You can define the version in the consuming project, but that's not the idiomatic way. It is an implementation dependency of your convention plugin. So you declare it as implementation dependency in the build script for your convention plugin, so in
common/build.gradle(.kts)
n
Copy code
buildscript {
  repositories {
    maven {
      url "<https://plugins.gradle.org/m2/>"
    }
  }
  dependencies {
    classpath "com.diffplug.spotless:spotless-plugin-gradle:6.18.0"
  }
}
This is what I had in the main project, but
buildscript
is not allowed in Groovy script plugins. I'm sure there's another way to express it (I've tried multiple)
v
Have a look at Jendrik's repository I linked you to. As I said, it is most likely more complex than you need it, and it uses composite builds, but whether you use the project as composite build or publish it to a repository does not make much difference, except for the
maven-publish
configuration to actually publish it. The actual implementation and usage is the same.
n
I did already take a look, you're certainly right about it being too complex for me
v
This is what I had in the main project, but
buildscript
is not allowed in Groovy script plugins. I'm sure there's another way to express it (I've tried multiple)
Well, you maybe didn't read what I wrote two message ago 🙂
Vampire [15:22 Uhr]
That is one of the "*almost* like normal build scripts" points.
In the precompiled script plugin you use it without version.
You can define the version in the consuming project, but that's not the idiomatic way.
It is an implementation dependency of your convention plugin.
So you declare it as implementation dependency in the build script for your convention plugin, so in
common/build.gradle(.kts)
n
Definitely did, maybe just not understanding it.
I mean, that's what I was trying to do
v
No, you said you tried to add it to the
buildscript
block of the precompiled script plugin. That is not even similar to what I said. 😉
n
So you declare it as implementation dependency in the build script for your convention plugin
I'm sure I'm just stupid, but this reads to me like the same thing. Unwrapping the
buildscript
block also yields
org.gradle.api.plugins.UnknownPluginException: Plugin with id 'com.diffplug.spotless' not found.
v
No, "the build script or the project building your convention plugin" is not nearly the same as "the
buildscript
block inside your convention plugin". I even told you the exact file where you put and what you put in there to make sure you don't misunderstand like that. 😉
n
Appreciate the red penciling
So does that not equate to the following?
Copy code
repositories {
    maven {
        url "<https://plugins.gradle.org/m2/>"
    }
}

dependencies {
    classpath "com.diffplug.spotless:spotless-plugin-gradle:6.18.0"
}
``````
Um, and putting the version in there is what seems to the same as propagating it to clients to me. I'm clearly too confused for this, thank you very much for your support
v
As this will give you "configuration classpath not found" and I said "implementation dependency", not "classpath dependency", no 🙂
is what seems to the same as propagating it to clients to me.
Why? It is part of the convention plugin build. The consuming project will not need to specify the version anywhere.
n
I'll leave this thread in case anybody feels free to hack on the git repos I spent some time preparing (seeing as it sounds like a ~2 min task to demonstrate) - unfortunately I've done so much reading of documentation, examples, and conversations, that everything just feels like disconnected advice at this point. Seeing a minimally working example is the only path forward to integrating my understanding at this point
v
Not sure what the problem is. Take your last code block, replace
classpath
by
implementation
, put that to the
common/build.gradle(.kts)
build script, then use the plugin without version in your convention plugin, that's it.
n
Added the changes: https://github.com/ndg-github/common/blob/main/build.gradle
Copy code
> Failed to apply plugin 'common'.
   > org.gradle.api.plugins.UnknownPluginException: Plugin with id 'com.diffplug.spotless' not found.
v
That's because you nested your plugin too deep. By having
common/buildSrc
you have yet another standalone build that is built separately to then by applied in
common/build.gradle
which is not what you actually want. You want your
common.gradle
in
src/main/groovy
and apply
groovy-gradle-plugin
in
common/build.gradle
. Then you can apply
common
in your
appX
builds. Besides that
common
is a bad name, custom convention plugins should always have some namespace (a dot in the name, or a package declaration in the precompiled script plugins). Namespaceless plugin IDs should be reserved for Gradle built-in plugins.
n
Thanks, yes,
common
was just quickly picked for the purposes of this PoC - not what I would keep. So I've moved the apply of
groovy-gradle-plugin
into the
common/build.gradle
(well,
/build.gradle
, being the repo root) Are you saying to
mv buildSrc/src/main/groovy/common.gradle src/main/groovy/common.gradle
essentially? Doing that yields
Plugin [id: 'common'] was not found in any of the following sources:
(which TBH, I'd expect, from doing that)
v
Yes I do and you of course remove applying
common
in
common/build.gradle
(just using
common/
to make sure I'm not talking about
appX/build.gradle
). You want to apply
common
in
appX/build.gradle
, not in
common/build.gradle
.
You cannot apply to the build building
common
the result of building
common
. That would be a hen-and-egg situation.
n
That makes sense to me now. I've explored enough bad routes that I've lost sense of good and bad
v
Just imagine
common
as a standalone version of
buildSrc
, which actually is exactly the case. So basically if you copy
buildSrc
out, rename it to
common
and add publishing configuration you are almost where you want to be.
n
Okay, so I've published to mavenLocal (https://github.com/ndg-github/common/blob/main/build.gradle) And a failed access from: https://github.com/ndg-github/app1/blob/main/build.gradle Now I'm not surprised it is failing to find the plugin, but I'm not quite sure on what the solution needs to look like
I'm assuming I need a
gradlePlugin
of some sort in `common/build.gradle`; and perhaps something else in
app1/build.gradle
I'm attempting something, but can't remember the name of the function that yields the gradle plugin repo URL
v
No,
common
is fine, you just did not specify the version of `common`to apply in
app1
If it is not coming from an included build / composite build, but from a repository, you have to specify a version.
In your case
0.1
n
Added that separately since my last message; I'm thinking I need something like this in `app1/settings.gradle`:
Copy code
pluginManagement {
    repositories {
        mavenLocal()
    }
}
Except also including the gradle plugin repo
v
Yes
gradlePluginPortal()
But additionally the version for the plugin
n
So many permutations of Google searches didn't turn that up. Maybe one that should have gone to GPT 😄
v
gradlePluginPortal()
is the default if you have nothing, but if you have anything you have to be explicit
n
Yup, I'm glad to be thinking of something correctly
So this leaves me with a new error message, which is progress:
Copy code
Execution failed for task ':tasks'.
> Could not create task ':spotlessJava'.
   > Could not resolve all files for configuration ':spotless865456303'.
      > Cannot resolve external dependency com.google.googlejavaformat:google-java-format:1.16.0 because no repositories are defined.
        Required by:
            project :
v
ChatGPT is not helpful anyway. It is good for giving answer that look nice and correct, but not for answer that are correct. It is not for nothing that answers from ChatGPT are banned from being posted on StackOverflow for example. ChatGPT is only good for things you could actually do yourself but are too lazy (the good lazy, not the bad one) as you have to undertand what he produced and need to fix the non-sense it put in. I've yet to see a helpful programming solution by it except for the most trival things. All I've seen so far was bullshit and with methods on APIs that never existed and so on. Besidest that its data base is more than 2 years old, so ancient in computer terms, especially for a rapid evolving thing like Gradle.
Copy code
Cannot resolve external dependency com.google.googlejavaformat:google-java-format:1.16.0 because no repositories are defined.
That most probably is because you have no repositories for
app1
. So either add it there or to your convention plugin.
n
Believe me, I never talk to GPT in areas I have technical competence in. I did say this was a last-ditch effort 😉
b
I'm following along as I'm in a very similar boat trying to fix up a multi-module project that started life as several individual projects and I've smooshed together into a monorepo. The worst part about wrong ChatGPT answers is that it answers as if it's entirely sure it is correct, where at least a person would have the sense to say they don't know.
☝️ 1
n
And GPT even failed for that. I was thinking it was a sufficiently narrow-scoped question. The key word to know is "portal".. forget that, and you're not finding it
Sweet Jesus it worked. Thank you for getting me there @Vampire
👌 1
b
To go with that github repo for idiomatic gradle, he also has a playlist going over a ton of stuff. https://www.youtube.com/playlist?list=PLWQK2ZdV4Yl2k2OmC_gsjDpdIBTN0qqkE
n
I just have to be honest, for some reason I find Gradle docs (and online resources) rather impenetrable. I can't think of any other software technology where I've felt that way
b
If you don't mind letting me know when you push your changes ndg. I'm looking over the idiomatic-gradle but it's like jumping into the deep end.
n
Yeah that's pushed now @BryanT 👍
🙏 1
Works perfectly 😄
@Vampire - last question for now before I leave my computer, and then re-look at again this with fresh eyes 🙂 You mentioned best-practice, that plugins should have dots in their name; in this case the plugin is using
rootProject.name
1. Would you suggest changing
rootProject.name
to `foo.common`; or another route without changing the
rootProject.name
itself? 2. I used a group ID of
com.example
for the artifact - should the plugin name therefore conventionally be
com.example.common
?
v
I'm not entirely sure what you mean by
rootProject.name
exactly here. But yeah, if you put your plugin in group
com.example
, having
com.example.common
or
com.example.build.common
or whatever surely sounds sensible.
n
So my understanding is that the plugin name is being implicitly defined by
rootProject.name
, which is inferred by the name of the project directory (
common
)
v
The plugin id for precompiled script plugins is inferred from its name and package. If it is the same as the root project name, that's mainly convention. And if the root project name is inferred by the directory, then you do not follow best practice. 😄 Every project has to have a
settings.gradle(.kts)
and that should define the root project name to be independent from directory name.
n
This would suggest to me I either need to set
rootProject.name
in
settings.gradle
(I don't think the value of
rootProject.name
is best-practice expected to contain dots?), or rather: concatenate the groupId with
rootProject.name
I see - I'll set
rootProject.name
to be
com.example.common
then, if that sounds sensible
v
No, previous plan did sound better. Project name should not contain dots.
n
Okay 🙂
Just trying to work out how to set the plugin name now Done 🙂