I'm wondering if someone can review an approach I'...
# community-support
d
I'm wondering if someone can review an approach I'm taking to share a maven repo declaration in a settings.gradle.kts file. I'll put code inside the thread.
Essentially, what I wish I could define at a top level in my
settings.gradle.kts
is this declaration for my artifact snapshots:
Copy code
fun RepositoryHandler.exampleSnapshots() {
    maven("<https://s01.oss.sonatype.org/content/repositories/snapshots/>") {
        content {
            includeGroupByRegex("com\\.example\\.stuff.*")
        }
    }
}
And important: I have snapshots both for some Gradle plugins AND normal library artifacts related to my project, so I'd want to reference this from both the
pluginManagement
and
dependencyResolutionManagement
blocks.
Here's what I've come up with that seems to work
Copy code
pluginManagement {
    repositories {
        gradlePluginPortal()
    }
}

dependencyResolutionManagement {
    repositories {
        mavenCentral()
        google()
    }
}

gradle.settingsEvaluated {
    fun RepositoryHandler.exampleSnapshots() { /* ... */ }
    pluginManagement.repositories { exampleSnapshots() }
    dependencyResolutionManagement.repositories { exampleSnapshots() }
}
If it were possible to declare top level functions directly inside a
settings.gradle.kts
file, well, that would be it. I'd be done! But I understand that the
pluginManagement
block is magical. Outside of that, I suspect that the Gradle idiomatic approach would be to create a Settings plugin, but looking into that, it looks a lot messier than I'd like. And here's a final wrinkle: I'm not actually writing code in my own project. I'm writing a README for my users, and I'm trying to suggest to them what code they can add to their project enable snapshots. I'm also providing some templates that users can build their projects on top of, and I'd like to have this code in there already, so that users could easily help us test snapshot versions if we ask them to.
So I'm trying to gauge the scale of hackiness here. From 1 (catapult that code into the sun please) to 10 (honestly, that's a pretty clean solution for snapshots), I'd love to get a sense where my approach falls as well as hear what a Gradle expert might do.
p
As a user I would just copy the maven repo twice than copying this workaround
👍 1
d
I'm a little worried that in the future we might have to update the regex and think that DRY is probably important with stuff like regexes?
p
I understand it, but at least for the subgroup regex there is also an incubating (could be stable…) api: includeGroupAndSubgroups
d
In my case, I have two groups: "com.varabyte.kobweb" and "com.varabyte.kobwebx"
The regex has been a nice way to one-liner that.
p
Oh okay
But Gradle is complex. And as a beginner, seeing, pluginManagement, normal dependencyResolutionManagement and then gradle.settingsEvaluated and pluginManagement again, I am out.
d
That's fair enough, but of course I'd add a helpful comment 🙂
But it is true that some people may already have projects that declare their repositories across multiple files (e.g. settings.gradle.kts and build.gradle.kts)
Copy code
pluginManagement {
    repositories {
        gradlePluginPortal()
    }
}

dependencyResolutionManagement {
    repositories {
        mavenCentral()
        google()
    }
}

// Snapshots added this way to share code across pluginManagement and dependencyResolutionManagement blocks.
// You cannot simply declare a top level function and call them from both places due to Gradle limitations.
gradle.settingsEvaluated {
    fun RepositoryHandler.kobwebSnapshots() {
        maven("<https://s01.oss.sonatype.org/content/repositories/snapshots/>") {
            content {
                includeGroupByRegex("com\\.varabyte\\.kobweb.*")
            }
        }
    }

    pluginManagement.repositories { kobwebSnapshots() }
    dependencyResolutionManagement.repositories { kobwebSnapshots() }
}
^ There's the final version of the proposed code.
Would you hate seeing that if it were in a prepared template?
Another approach would be to just ditch the regex and be sad about that:
Copy code
pluginManagement {
    repositories {
        gradlePluginPortal()
        maven("<https://s01.oss.sonatype.org/content/repositories/snapshots/>") 
    }
}

dependencyResolutionManagement {
    repositories {
        mavenCentral()
        google()
        maven("<https://s01.oss.sonatype.org/content/repositories/snapshots/>") 
    }
}
p
I don’t hate anything. And there is also snapshotOnly, but that includes other snapshot dependencies too, with the regex that would fail.
Don’t know why maven has mavenContent and content besides MavenRepositoryContentDescriptor extends RepositoryContentDescriptor 🤔
d
I'm not finding out how to set
snapshotOnly
, and initial Google searches are failing me. Am I missing something obvious?
Ah,
mavenContent
Copy code
maven("<https://s01.oss.sonatype.org/content/repositories/snapshots/>") {
   content {
      includeGroupByRegex("com\\.varabyte\\.kobweb.*")
   }
   mavenContent { 
       snapshotsOnly()
   }
}
v
Some points: •
mavenContent
is a specialization of
content
so just put both lines in
mavenContent
and ditch
content
.
mavenContent
can just do more than
content
(namely configuring "snapshots only" and "releases only") • The problem with the
settingsEvaluated
construct is, it is ugly • The next problem with the
settingsEvaluated
construct is, it is confusing to the non-expert • Yet another problem with the
settingsEvaluated
construct is, that it does not work if you need to resolve a settings plugin from that repository as this is executed after the settings plugins are resolved and so would only work for project plugins, but that might be ok for your use-case of course Here a likewise ugly alternative that behaves better, as it also works for settings plugins and has less repetition:
Copy code
// the plugin management block is evaluated first separately, do not change this to
// listOf(pluginManagement.repositories, dependencyResolutionManagement.repositories)
// instead that would change the semantics
pluginManagement {
    listOf(repositories, dependencyResolutionManagement.repositories).forEach { repositories ->
        repositories.apply {
            maven("<https://s01.oss.sonatype.org/content/repositories/snapshots/>") {
                mavenContent {
                    includeGroupByRegex("com\\.varabyte\\.kobweb.*")
                    snapshotsOnly()
                }
            }
        }
    }
}
You cannot use anything from outside the
pluginManagement
block inside (just like
plugins
block or
buildscript
block or
initscript
block) but you can do configuration you would do outside of it inside.
d
Thank you! I'll give that a try tomorrow
👌 1
It was promising but I had a few issues with it compared to the
settingsEvaluated
approach (although don't get me wrong, I do agree with all your points about why
settingsEvaluated
can be problematic) 1. (Minor) I had to jam the logic into the middle of the existing
pluginManagement
block (Gradle complains if you declare more than one). Before, having a totally separated code block meant I could tell users to just paste some code blindly in their settings file and it would just work, and if they wanted to comment out / delete it later, it would be pretty easy for them to do so. 2. (Minor) The comment you left about
repositories
vs
pluginManagement.repositories
feels itself nuanced in a confusing way. 3. (Major?) Your code declares the snapshot repository BEFORE the
dependencyResolutionManagement
block gets a chance to run, which would give the snapshot repository precedence over the
mavenCentral
and
google
ones. Here, this is technically unlikely to actually cause problems (because my snapshot artifacts will never be in maven central or google locations), but my intention is definitely to treat the snapshot URL as a final fallback, not be first in the list. I think in general I have a better understanding now of why I should avoid
settingsEvaluated
but for this specific use-case (about declaring a snapshot repository just for local development purposes), I'm thinking I may just leave the suggestion as is.
v
🤷‍♂️
d
Sorry!
v
What for? 🙂
d
For disregarding your advice 🙂
v
If that would majorly bother me, I couldn't provide help in communities in the internet without getting a heartattack per week. 😄
I tell my opinion and advice, what you make out of it is up to you, you have to live with the consequences. 😄
d
FWIW you're a legend between a few of us when we talk about Gradle stuff. "WWVD" is a question we sometimes ask each other. Your advice on countless threads has influenced our Gradle scripts.
v
❤️
But also with my advices like with all the other stuff on the www, disregard it if it is too old. 😄 Also I have either bad advice because not knowing better, or more often things changed since then. 🙂
👍 1