diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..7b93509 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,24 @@ +/* + * Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com) + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + buildsrc.conventions.base +} + +description = "A simple defensive library to encode/decode URL components" +group = "net.thauvin.erik" +version = "1.3.1-SNAPSHOT" diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 0000000..be67fdf --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + `kotlin-dsl` +} + +dependencies { + implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0") + implementation("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.5.0.2730") + implementation("org.jetbrains.dokka:dokka-gradle-plugin:1.7.20") +} diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts new file mode 100644 index 0000000..bf6ac65 --- /dev/null +++ b/buildSrc/settings.gradle.kts @@ -0,0 +1,16 @@ +rootProject.name = "buildSrc" + +pluginManagement { + repositories { + mavenCentral() + gradlePluginPortal() + } +} + +@Suppress("UnstableApiUsage") +dependencyResolutionManagement { + repositories { + mavenCentral() + gradlePluginPortal() + } +} diff --git a/buildSrc/src/main/kotlin/buildsrc/conventions/base.gradle.kts b/buildSrc/src/main/kotlin/buildsrc/conventions/base.gradle.kts new file mode 100644 index 0000000..0ef8540 --- /dev/null +++ b/buildSrc/src/main/kotlin/buildsrc/conventions/base.gradle.kts @@ -0,0 +1,18 @@ +package buildsrc.conventions + +/** common config for all subprojects */ + +plugins { + base +} + +if (project != rootProject) { + project.version = rootProject.version + project.group = rootProject.group +} + +tasks.withType().configureEach { + // https://docs.gradle.org/current/userguide/working_with_files.html#sec:reproducible_archives + isPreserveFileTimestamps = false + isReproducibleFileOrder = true +} diff --git a/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-base.gradle.kts b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-base.gradle.kts new file mode 100644 index 0000000..4af978b --- /dev/null +++ b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-base.gradle.kts @@ -0,0 +1,45 @@ +package buildsrc.conventions.lang + +import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget + + +/** + * Base configuration for all Kotlin/Multiplatform conventions. + * + * This plugin does not enable any Kotlin target. To enable a target in a subproject, prefer applying specific Kotlin + * target convention plugins. + */ + +plugins { + id("buildsrc.conventions.base") + kotlin("multiplatform") +} + + +kotlin { + jvmToolchain(11) + + targets.configureEach { + compilations.configureEach { + kotlinOptions { + // nothin' yet + } + } + } + + // configure all Kotlin/JVM Tests to use JUnit + targets.withType().configureEach { + testRuns.configureEach { + executionTask.configure { + useJUnitPlatform() + } + } + } + + sourceSets.configureEach { + languageSettings { +// languageVersion = +// apiVersion = + } + } +} diff --git a/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-js.gradle.kts b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-js.gradle.kts new file mode 100644 index 0000000..2a0034a --- /dev/null +++ b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-js.gradle.kts @@ -0,0 +1,18 @@ +package buildsrc.conventions.lang + +/** conventions for a Kotlin/JS subproject */ + +plugins { + id("buildsrc.conventions.lang.kotlin-multiplatform-base") +} + +kotlin { + targets { + js(IR) { + browser() + nodejs() + } + } +} + +relocateKotlinJsStore() diff --git a/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-jvm.gradle.kts b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-jvm.gradle.kts new file mode 100644 index 0000000..6bbef24 --- /dev/null +++ b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-jvm.gradle.kts @@ -0,0 +1,11 @@ +package buildsrc.conventions.lang + +plugins { + id("buildsrc.conventions.lang.kotlin-multiplatform-base") +} + +kotlin { + jvm { + withJava() + } +} diff --git a/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-native.gradle.kts b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-native.gradle.kts new file mode 100644 index 0000000..7e8bb2a --- /dev/null +++ b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlin-multiplatform-native.gradle.kts @@ -0,0 +1,102 @@ +package buildsrc.conventions.lang + +/** conventions for a Kotlin/Native subproject */ + +plugins { + id("buildsrc.conventions.lang.kotlin-multiplatform-base") +} + +kotlin { + + // Native targets all extend commonMain and commonTest. + // + // Some targets (ios, tvos, watchos) are shortcuts provided by the Kotlin DSL, that + // provide additional targets, except for 'simulators' which must be defined manually. + // https://kotlinlang.org/docs/multiplatform-share-on-platforms.html#use-target-shortcuts + // + // common/ + // └── native/ + // ├── linuxX64 + // ├── mingwX64 + // ├── macosX64 + // ├── macosArm64 + // ├── ios/ (shortcut) + // │ ├── iosArm64 + // │ ├── iosX64 + // │ └── iosSimulatorArm64 + // ├── tvos/ (shortcut) + // │ ├── tvosArm64 + // │ ├── tvosX64 + // │ └── tvosSimulatorArm64Main + // └── watchos/ (shortcut) + // ├── watchosArm32 + // ├── watchosArm64 + // ├── watchosX64 + // └── watchosSimulatorArm64Main + + targets { + linuxX64() + + mingwX64() + + macosX64() + macosArm64() + + // https://kotlinlang.org/docs/multiplatform-share-on-platforms.html#use-target-shortcuts + ios() // iosArm64, iosX64 + watchos() // watchosArm32, watchosArm64, watchosX64 + tvos() // tvosArm64, tvosX64 + + iosSimulatorArm64() + tvosSimulatorArm64() + watchosSimulatorArm64() + } + + @Suppress("UNUSED_VARIABLE") + sourceSets { + val commonMain by getting {} + val commonTest by getting {} + + val nativeMain by creating { dependsOn(commonMain) } + val nativeTest by creating { dependsOn(commonTest) } + + // Linux + val linuxX64Main by getting { dependsOn(nativeMain) } + val linuxX64Test by getting { dependsOn(nativeTest) } + + // Windows - MinGW + val mingwX64Main by getting { dependsOn(nativeMain) } + val mingwX64Test by getting { dependsOn(nativeTest) } + + // Apple - macOS + val macosArm64Main by getting { dependsOn(nativeMain) } + val macosArm64Test by getting { dependsOn(nativeTest) } + + val macosX64Main by getting { dependsOn(nativeMain) } + val macosX64Test by getting { dependsOn(nativeTest) } + + // Apple - iOS + val iosMain by getting { dependsOn(nativeMain) } + val iosTest by getting { dependsOn(nativeTest) } + +// val iosSimulatorArm64Main by getting { dependsOn(iosMain) } +// val iosSimulatorArm64Test by getting { dependsOn(iosTest) } + +// // Apple - tvOS +// val tvosMain by getting { dependsOn(nativeMain) } +// val tvosTest by getting { dependsOn(nativeTest) } +// +// val tvosSimulatorArm64Main by getting { dependsOn(tvosMain) } +// val tvosSimulatorArm64Test by getting { dependsOn(tvosTest) } +// +// // Apple - watchOS +// val watchosMain by getting { dependsOn(nativeMain) } +// val watchosTest by getting { dependsOn(nativeTest) } +// +// val watchosSimulatorArm64Main by getting { dependsOn(watchosMain) } +// val watchosSimulatorArm64Test by getting { dependsOn(watchosTest) } + + // val iosArm32Main by getting { dependsOn(desktopMain) } + // val iosArm32Test by getting { dependsOn(nativeTest) } + } +} diff --git a/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlinJsExtensions.kt b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlinJsExtensions.kt new file mode 100644 index 0000000..eefdc94 --- /dev/null +++ b/buildSrc/src/main/kotlin/buildsrc/conventions/lang/kotlinJsExtensions.kt @@ -0,0 +1,18 @@ +package buildsrc.conventions.lang + +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension + +/** + * `kotlin-js` and `kotlin-multiplatform` plugins adds a directory in the root-dir for the Yarn + * lockfile. That's a bit annoying. It's a little neater if it's in the Gradle dir, next to the + * version catalog. + */ +internal fun Project.relocateKotlinJsStore() { + afterEvaluate { + rootProject.extensions.configure { + lockFileDirectory = project.rootDir.resolve("gradle/kotlin-js-store") + } + } +} diff --git a/buildSrc/src/main/kotlin/buildsrc/conventions/publishing.gradle.kts b/buildSrc/src/main/kotlin/buildsrc/conventions/publishing.gradle.kts new file mode 100644 index 0000000..4c26d99 --- /dev/null +++ b/buildSrc/src/main/kotlin/buildsrc/conventions/publishing.gradle.kts @@ -0,0 +1,102 @@ +/* + * Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com) + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package buildsrc.conventions + +import org.gradle.api.tasks.bundling.Jar +import org.gradle.kotlin.dsl.creating +import org.gradle.kotlin.dsl.getValue +import org.gradle.kotlin.dsl.version + +plugins { + id("maven-publish") + id("signing") + id("org.jetbrains.dokka") +} + +val gitHub = "ethauvin/${rootProject.name}" +val mavenUrl = "https://github.com/$gitHub" + +publishing { + publications { + withType().configureEach { + pom { + name.set("UrlEncoder for Kotlin") + description.set(project.description) + url.set(mavenUrl) + licenses { + license { + name.set("The Apache License, Version 2.0") + url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") + } + } + developers { + developer { + id.set("gbevin") + name.set("Geert Bevin") + email.set("gbevin@uwyn.com") + url.set("https://github.com/gbevin") + } + developer { + id.set("ethauvin") + name.set("Erik C. Thauvin") + email.set("erik@thauvin.net") + url.set("https://erik.thauvin.net/") + } + } + scm { + connection.set("scm:git://github.com/$gitHub.git") + developerConnection.set("scm:git@github.com:$gitHub.git") + url.set(mavenUrl) + } + issueManagement { + system.set("GitHub") + url.set("$mavenUrl/issues") + } + } + } + } + repositories { + maven( + if (project.version.toString().contains("SNAPSHOT")) { + uri("https://oss.sonatype.org/content/repositories/snapshots/") + } else { + uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/") + } + ) { + name = "ossrh" + credentials(PasswordCredentials::class) + } + } +} + +signing { + useGpgCmd() + sign(publishing.publications) +} + + +// https://youtrack.jetbrains.com/issue/KT-46466 +val signingTasks = tasks.withType() +tasks.withType().configureEach { + dependsOn(signingTasks) +} + +val javadocJar by tasks.registering(Jar::class) { + dependsOn(tasks.dokkaJavadoc) + from(tasks.dokkaJavadoc) + archiveClassifier.set("javadoc") +} diff --git a/buildSrc/src/main/kotlin/buildsrc/conventions/sonarqube.gradle.kts b/buildSrc/src/main/kotlin/buildsrc/conventions/sonarqube.gradle.kts new file mode 100644 index 0000000..80ce521 --- /dev/null +++ b/buildSrc/src/main/kotlin/buildsrc/conventions/sonarqube.gradle.kts @@ -0,0 +1,33 @@ +/* + * Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com) + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package buildsrc.conventions + +plugins { + id("org.sonarqube") +} + +sonarqube { + properties { + property("sonar.projectName", rootProject.name) + property("sonar.projectKey", "ethauvin_${rootProject.name}") + property("sonar.organization", "ethauvin-github") + property("sonar.host.url", "https://sonarcloud.io") + property("sonar.sourceEncoding", "UTF-8") + property("sonar.coverage.jacoco.xmlReportPaths", "${project.buildDir}/reports/kover/xml/report.xml") + } +} diff --git a/buildSrc/src/main/kotlin/buildsrc/utils/Rife2TestListener.kt b/buildSrc/src/main/kotlin/buildsrc/utils/Rife2TestListener.kt new file mode 100644 index 0000000..2fe062f --- /dev/null +++ b/buildSrc/src/main/kotlin/buildsrc/utils/Rife2TestListener.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com) + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package buildsrc.utils + +import org.gradle.api.tasks.testing.TestDescriptor +import org.gradle.api.tasks.testing.TestListener +import org.gradle.api.tasks.testing.TestResult +import java.net.URI +import java.net.http.HttpClient +import java.net.http.HttpRequest +import java.net.http.HttpResponse + +class Rife2TestListener( + private val testBadgeApiKey: String? +) : TestListener { + override fun beforeTest(p0: TestDescriptor?) = Unit + override fun beforeSuite(p0: TestDescriptor?) = Unit + override fun afterTest(desc: TestDescriptor, result: TestResult) = Unit + override fun afterSuite(desc: TestDescriptor, result: TestResult) { + if (desc.parent == null) { + val passed = result.successfulTestCount + val failed = result.failedTestCount + val skipped = result.skippedTestCount + + if (testBadgeApiKey != null) { + println(testBadgeApiKey) + val response: HttpResponse = HttpClient.newHttpClient() + .send( + HttpRequest.newBuilder() + .uri( + URI( + "https://rife2.com/tests-badge/update/net.thauvin.erik/urlencoder?" + + "apiKey=$testBadgeApiKey&" + + "passed=$passed&" + + "failed=$failed&" + + "skipped=$skipped" + ) + ) + .POST(HttpRequest.BodyPublishers.noBody()) + .build(), HttpResponse.BodyHandlers.ofString() + ) + println("RESPONSE: ${response.statusCode()}") + println(response.body()) + } + } + } +} diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 5b12abf..9b81aef 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -1,11 +1,8 @@ +import buildsrc.utils.Rife2TestListener import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent import org.jetbrains.dokka.gradle.DokkaTask import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import java.net.URI -import java.net.http.HttpClient -import java.net.http.HttpRequest -import java.net.http.HttpResponse plugins { @@ -14,30 +11,20 @@ plugins { id("io.gitlab.arturbosch.detekt") version "1.22.0" id("java-library") id("maven-publish") - id("org.jetbrains.dokka") version "1.7.20" - id("org.jetbrains.kotlin.jvm") version "1.8.0" + id("org.jetbrains.kotlin.jvm") id("org.jetbrains.kotlinx.kover") version "0.6.1" - id("org.sonarqube") version "3.5.0.2730" - id("signing") + + buildsrc.conventions.publishing + buildsrc.conventions.sonarqube } -description = "A simple defensive library to encode/decode URL components" -group = "net.thauvin.erik" -version = "1.3.1-SNAPSHOT" - - val mavenName = "UrlEncoder" -val deployDir = "deploy" +val deployDir = project.layout.projectDirectory.dir("deploy") val gitHub = "ethauvin/${rootProject.name}" val mavenUrl = "https://github.com/$gitHub" val publicationName = "mavenJava" val myClassName = "$group.${rootProject.name}.$mavenName" -repositories { - mavenCentral() - maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } -} - dependencies { // testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.25") testImplementation("org.junit.jupiter:junit-jupiter:5.9.1") @@ -57,23 +44,6 @@ application { mainClass.set(myClassName) } -sonarqube { - properties { - property("sonar.projectName", rootProject.name) - property("sonar.projectKey", "ethauvin_${rootProject.name}") - property("sonar.organization", "ethauvin-github") - property("sonar.host.url", "https://sonarcloud.io") - property("sonar.sourceEncoding", "UTF-8") - property("sonar.coverage.jacoco.xmlReportPaths", "${project.buildDir}/reports/kover/xml/report.xml") - } -} - -val javadocJar by tasks.creating(Jar::class) { - dependsOn(tasks.dokkaJavadoc) - from(tasks.dokkaJavadoc) - archiveClassifier.set("javadoc") -} - tasks { jar { manifest { @@ -102,58 +72,23 @@ tasks { } test { - useJUnitPlatform() - addTestListener(object : TestListener { - override fun beforeTest(p0: TestDescriptor?) = Unit - override fun beforeSuite(p0: TestDescriptor?) = Unit - override fun afterTest(desc: TestDescriptor, result: TestResult) = Unit - override fun afterSuite(desc: TestDescriptor, result: TestResult) { - if (desc.parent == null) { - val passed = result.successfulTestCount - val failed = result.failedTestCount - val skipped = result.skippedTestCount - - if (project.properties["testsBadgeApiKey"] != null) { - val apiKey = project.properties["testsBadgeApiKey"] - println(apiKey) - val response: HttpResponse = HttpClient.newHttpClient() - .send( - HttpRequest.newBuilder() - .uri( - URI( - "https://rife2.com/tests-badge/update/net.thauvin.erik/urlencoder?" + - "apiKey=$apiKey&" + - "passed=$passed&" + - "failed=$failed&" + - "skipped=$skipped" - ) - ) - .POST(HttpRequest.BodyPublishers.noBody()) - .build(), HttpResponse.BodyHandlers.ofString() - ) - println("RESPONSE: ${response.statusCode()}") - println(response.body()) - } - } - } - }) + addTestListener(Rife2TestListener(project.properties["testsBadgeApiKey"]?.toString())) } withType { + useJUnitPlatform() testLogging { exceptionFormat = TestExceptionFormat.FULL events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED) } } - withType { + withType().configureEach { destination = file("$projectDir/pom.xml") } clean { - doLast { - project.delete(fileTree(deployDir)) - } + delete(deployDir) } withType().configureEach { @@ -164,7 +99,7 @@ tasks { } } - val copyToDeploy by registering(Copy::class) { + val copyToDeploy by registering(Sync::class) { from(configurations.runtimeClasspath) { exclude("annotations-*.jar") } @@ -173,12 +108,11 @@ tasks { } register("deploy") { - description = "Copies all needed files to the $deployDir directory." + description = "Copies all needed files to the 'deploy' directory." group = PublishingPlugin.PUBLISH_TASK_GROUP - dependsOn(clean, build, jar) + dependsOn(build, jar) outputs.dir(deployDir) inputs.files(copyToDeploy) - mustRunAfter(clean) } "sonar" { @@ -188,58 +122,10 @@ tasks { publishing { publications { - create(publicationName) { + create("mavenJava") { from(components["java"]) - artifactId = rootProject.name - artifact(javadocJar) - pom { - name.set("$mavenName for Kotlin") - description.set(project.description) - url.set(mavenUrl) - licenses { - license { - name.set("The Apache License, Version 2.0") - url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") - } - } - developers { - developer { - id.set("gbevin") - name.set("Geert Bevin") - email.set("gbevin@uwyn.com") - url.set("https://github.com/gbevin") - } - developer { - id.set("ethauvin") - name.set("Erik C. Thauvin") - email.set("erik@thauvin.net") - url.set("https://erik.thauvin.net/") - } - } - scm { - connection.set("scm:git://github.com/$gitHub.git") - developerConnection.set("scm:git@github.com:$gitHub.git") - url.set(mavenUrl) - } - issueManagement { - system.set("GitHub") - url.set("$mavenUrl/issues") - } - } - } - } - repositories { - maven { - name = "ossrh" - url = if (project.version.toString().contains("SNAPSHOT")) - uri("https://oss.sonatype.org/content/repositories/snapshots/") else - uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/") - credentials(PasswordCredentials::class) + artifactId = "${rootProject.name}-lib" + artifact(tasks.javadocJar) } } } - -signing { - useGpgCmd() - sign(publishing.publications[publicationName]) -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 0cb10ee..e75db1d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,12 +1,25 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * The settings file is used to specify which projects to include in your build. - * - * Detailed information about configuring a multi-project build in Gradle can be found - * in the user manual at https://docs.gradle.org/7.6/userguide/multi_project_builds.html - * This project uses @Incubating APIs which are subject to change. - */ - rootProject.name = "urlencoder" -include("lib") + +pluginManagement { + repositories { + mavenCentral() + gradlePluginPortal() + } +} + +@Suppress("UnstableApiUsage") +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) + + repositories { + mavenCentral() + maven("https://oss.sonatype.org/content/repositories/snapshots") { + name = "Sonatype Snapshots" + mavenContent { snapshotsOnly() } + } + } +} + +include( + ":lib", +)