From d3d9ae627e0a303974538cda38239a8882b29820 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Thu, 10 Sep 2026 18:05:17 +0200 Subject: [PATCH] Make the aggregation non-lenient by default --- nmcp/api/nmcp.api | 1 + .../kotlin/nmcp/NmcpAggregationExtension.kt | 10 ++++++++ nmcp/src/main/kotlin/nmcp/NmcpExtension.kt | 9 ++++---- .../DefaultNmcpAggregationExtension.kt | 23 ++++++++++++------- .../nmcp/internal/DefaultNmcpSettings.kt | 22 ++++++++++-------- nmcp/src/test/kotlin/MainTest.kt | 21 +++++++++++++++++ .../testProjects/non-lenient/build.gradle.kts | 21 +++++++++++++++++ nmcp/testProjects/non-lenient/dir1/file1 | 1 + nmcp/testProjects/non-lenient/dir2/file2 | 1 + .../non-lenient/settings.gradle.kts | 6 +++++ scripts/update-repo.main.kts | 3 +++ 11 files changed, 96 insertions(+), 22 deletions(-) create mode 100644 nmcp/testProjects/non-lenient/build.gradle.kts create mode 100644 nmcp/testProjects/non-lenient/dir1/file1 create mode 100644 nmcp/testProjects/non-lenient/dir2/file2 create mode 100644 nmcp/testProjects/non-lenient/settings.gradle.kts diff --git a/nmcp/api/nmcp.api b/nmcp/api/nmcp.api index efd4e01..365e0e0 100644 --- a/nmcp/api/nmcp.api +++ b/nmcp/api/nmcp.api @@ -21,6 +21,7 @@ public abstract interface class nmcp/NmcpAggregationExtension { public abstract fun getAllFiles ()Lorg/gradle/api/file/FileCollection; public abstract fun getAllowDuplicateProjectNames ()Lorg/gradle/api/provider/Property; public abstract fun getAllowEmptyAggregation ()Lorg/gradle/api/provider/Property; + public abstract fun getLenient ()Lorg/gradle/api/provider/Property; public abstract fun getPublishAllChecksums ()Lorg/gradle/api/provider/Property; public abstract fun localRepository (Lorg/gradle/api/Action;)V public abstract fun publishAllProjectsProbablyBreakingProjectIsolation ()V diff --git a/nmcp/src/main/kotlin/nmcp/NmcpAggregationExtension.kt b/nmcp/src/main/kotlin/nmcp/NmcpAggregationExtension.kt index 7ce7b2b..ebfd5e3 100644 --- a/nmcp/src/main/kotlin/nmcp/NmcpAggregationExtension.kt +++ b/nmcp/src/main/kotlin/nmcp/NmcpAggregationExtension.kt @@ -71,4 +71,14 @@ interface NmcpAggregationExtension { * Default: false */ val publishAllChecksums: Property + + /** + * By default, the aggregation is not lenient so that configuration errors are easier to debug. + * Sometimes, it's easier to just do `allprojects {}` and collect all subprojects, even those that do not apply the `com.gradleup.nmcp` plugin. + * The settings plugin uses this for an example. + * + * In those cases, set `lenient.set(true)` to ignore those subprojects. + * + */ + val lenient: Property } diff --git a/nmcp/src/main/kotlin/nmcp/NmcpExtension.kt b/nmcp/src/main/kotlin/nmcp/NmcpExtension.kt index 89933db..e20bd21 100644 --- a/nmcp/src/main/kotlin/nmcp/NmcpExtension.kt +++ b/nmcp/src/main/kotlin/nmcp/NmcpExtension.kt @@ -21,10 +21,9 @@ interface NmcpExtension { * * Use this to add publications whose files are not known until execution time. * - * @param files the files to be added. - * The given paths are evaluated as per [org.gradle.api.Project.files]. - * Typically, [files] is built from a [org.gradle.api.file.FileTree] or - * a [org.gradle.api.file.DirectoryProperty] so that the files also contain their relative path. + * @param artifactNotation the files to be added. + * The given paths are evaluated as per [org.gradle.api.artifacts.dsl.ArtifactHandler.add]. + * Typically, [artifactNotation] is a directory or a task producing a directory. */ - fun extraFiles(files: Any) + fun extraFiles(artifactNotation: Any) } diff --git a/nmcp/src/main/kotlin/nmcp/internal/DefaultNmcpAggregationExtension.kt b/nmcp/src/main/kotlin/nmcp/internal/DefaultNmcpAggregationExtension.kt index bf0d9d1..8f386bb 100644 --- a/nmcp/src/main/kotlin/nmcp/internal/DefaultNmcpAggregationExtension.kt +++ b/nmcp/src/main/kotlin/nmcp/internal/DefaultNmcpAggregationExtension.kt @@ -26,7 +26,7 @@ import org.gradle.api.provider.Provider internal abstract class DefaultNmcpAggregationExtension(private val project: Project) : NmcpAggregationExtension { private val spec = project.objects.newInstance(CentralPortalOptions::class.java) - internal val consumerConfiguration = project.configurations.create(nmcpConsumerConfigurationName) { + internal val consumerConfiguration = project.configurations.register(nmcpConsumerConfigurationName) { it.isCanBeResolved = true it.isCanBeConsumed = false @@ -40,13 +40,18 @@ internal abstract class DefaultNmcpAggregationExtension(private val project: Pro init { allFiles.from( consumerConfiguration - .incoming - .artifactView { it.lenient(true) } - .artifacts - .resolvedArtifacts .map { - it.filter(::isCompatible).map { it.file } - }, + it.incoming + .artifactView { + it.lenient(lenient.getOrElse(false)) + } + .artifacts + .resolvedArtifacts + .map { + it.filter(::isCompatible).map { it.file } + } + } + ) zipProvider = project.registerPublishToCentralPortalTasks( kind = Kind.aggregation, @@ -99,7 +104,9 @@ internal abstract class DefaultNmcpAggregationExtension(private val project: Pro aproject.pluginManager.withPlugin("maven-publish") { aproject.pluginManager.apply("com.gradleup.nmcp") - consumerConfiguration.dependencies.add(aproject.dependencies.create(aproject)) + consumerConfiguration.configure { + it.dependencies.add(aproject.dependencies.create(aproject)) + } } } } diff --git a/nmcp/src/main/kotlin/nmcp/internal/DefaultNmcpSettings.kt b/nmcp/src/main/kotlin/nmcp/internal/DefaultNmcpSettings.kt index 441723a..2a63614 100644 --- a/nmcp/src/main/kotlin/nmcp/internal/DefaultNmcpSettings.kt +++ b/nmcp/src/main/kotlin/nmcp/internal/DefaultNmcpSettings.kt @@ -22,15 +22,19 @@ abstract class DefaultNmcpSettings(settings: Settings): NmcpSettings { if (project.rootProject == project) { project.pluginManager.apply("com.gradleup.nmcp.aggregation") - project.extensions.getByType(NmcpAggregationExtension::class.java).centralPortal { - it.username.set(spec.username) - it.password.set(spec.password) - it.publishingType.set(spec.publishingType) - it.publicationName.set(spec.publicationName) - it.validationTimeout.set(spec.validationTimeout) - it.publishingTimeout.set(spec.publishingTimeout) - it.baseUrl.set(spec.baseUrl) - it.uploadSnapshotsParallelism.set(spec.uploadSnapshotsParallelism) + project.extensions.getByType(NmcpAggregationExtension::class.java).apply { + // subprojects may not all apply com.gradleup.nmcp + lenient.set(true) + centralPortal { + it.username.set(spec.username) + it.password.set(spec.password) + it.publishingType.set(spec.publishingType) + it.publicationName.set(spec.publicationName) + it.validationTimeout.set(spec.validationTimeout) + it.publishingTimeout.set(spec.publishingTimeout) + it.baseUrl.set(spec.baseUrl) + it.uploadSnapshotsParallelism.set(spec.uploadSnapshotsParallelism) + } } project.allprojects { diff --git a/nmcp/src/test/kotlin/MainTest.kt b/nmcp/src/test/kotlin/MainTest.kt index 1953a71..0be0a9e 100644 --- a/nmcp/src/test/kotlin/MainTest.kt +++ b/nmcp/src/test/kotlin/MainTest.kt @@ -1,5 +1,6 @@ import java.io.File import kotlin.test.Test +import kotlin.test.assertFalse import org.gradle.testkit.runner.GradleRunner class MainTest { @@ -38,4 +39,24 @@ class MainTest { assert(result.output.contains("Nmcp: there are no files to publish")) } + + @Test + fun nonLenient() { + val dst = File("build/testProject") + val src = File("testProjects/non-lenient") + + dst.deleteRecursively() + dst.mkdirs() + + src.copyRecursively(dst, overwrite = true) + + val result = GradleRunner.create() + .withProjectDir(dst) + .withArguments("nmcpZipAggregation") + .withDebug(true) + .buildAndFail() + + assertFalse(result.output.contains("there are no files to publish")) + assert(result.output.contains("Expected task 'foo' output files to contain exactly one file, however, it contains more than one file")) + } } diff --git a/nmcp/testProjects/non-lenient/build.gradle.kts b/nmcp/testProjects/non-lenient/build.gradle.kts new file mode 100644 index 0000000..0bd7fc8 --- /dev/null +++ b/nmcp/testProjects/non-lenient/build.gradle.kts @@ -0,0 +1,21 @@ +plugins { + id("maven-publish") + id("com.gradleup.nmcp").version("1.6.3-SNAPSHOT") + id("com.gradleup.nmcp.aggregation").version("1.6.3-SNAPSHOT") +} + +val fooTask = tasks.register("foo") { + outputs.dir(layout.projectDirectory.file("dir1")) + outputs.dir(layout.projectDirectory.file("dir2")) +} + +nmcp { + /** + * error: the task contains several outputs and therefore cannot be added as an artifact + */ + extraFiles(fooTask) +} + +dependencies { + nmcpAggregation(project) +} diff --git a/nmcp/testProjects/non-lenient/dir1/file1 b/nmcp/testProjects/non-lenient/dir1/file1 new file mode 100644 index 0000000..15b8f2a --- /dev/null +++ b/nmcp/testProjects/non-lenient/dir1/file1 @@ -0,0 +1 @@ +hello1 diff --git a/nmcp/testProjects/non-lenient/dir2/file2 b/nmcp/testProjects/non-lenient/dir2/file2 new file mode 100644 index 0000000..23294b0 --- /dev/null +++ b/nmcp/testProjects/non-lenient/dir2/file2 @@ -0,0 +1 @@ +hello2 \ No newline at end of file diff --git a/nmcp/testProjects/non-lenient/settings.gradle.kts b/nmcp/testProjects/non-lenient/settings.gradle.kts new file mode 100644 index 0000000..087fd30 --- /dev/null +++ b/nmcp/testProjects/non-lenient/settings.gradle.kts @@ -0,0 +1,6 @@ +pluginManagement { + listOf(repositories, dependencyResolutionManagement.repositories).forEach { + it.mavenCentral() + it.maven("../../../build/m2") + } +} diff --git a/scripts/update-repo.main.kts b/scripts/update-repo.main.kts index 7046e55..607f398 100755 --- a/scripts/update-repo.main.kts +++ b/scripts/update-repo.main.kts @@ -18,6 +18,9 @@ updateRepo( file("nmcp/testProjects/empty-aggregation/build.gradle.kts") { replacePluginVersion("com.gradleup.nmcp.aggregation") } + file("nmcp/testProjects/non-lenient/build.gradle.kts") { + replacePluginVersion("com.gradleup.nmcp.aggregation") + } }, setVersionInDocs = { file("docs/src/content/docs/index.mdx") {