Only allow single publish setting for KMP libraries and publish all declared targets when publish is configured

Bug: 235594579
Test: Existing builds continue to work and produce correct artifacts
Change-Id: Ieca07201b198b084267c0c5645714f7e6420b6ec
diff --git a/buildSrc-tests/src/test/kotlin/androidx/build/AndroidXSelfTestProject.kt b/buildSrc-tests/src/test/kotlin/androidx/build/AndroidXSelfTestProject.kt
index 55a37f1..8923ff1 100644
--- a/buildSrc-tests/src/test/kotlin/androidx/build/AndroidXSelfTestProject.kt
+++ b/buildSrc-tests/src/test/kotlin/androidx/build/AndroidXSelfTestProject.kt
@@ -90,9 +90,7 @@
                |}
                |
                |androidx {
-               |  type = LibraryType.kmpLibrary {
-               |    jvm = Publish.SNAPSHOT_AND_RELEASE
-               |  }
+               |  type = LibraryType.KMP_LIBRARY
                |  mavenVersion = new Version("1.2.3")
                |  mavenGroup = new LibraryGroup("cubane", null)
                |}
diff --git a/buildSrc-tests/src/test/kotlin/androidx/build/PublishExtensionTest.kt b/buildSrc-tests/src/test/kotlin/androidx/build/PublishExtensionTest.kt
deleted file mode 100644
index baf1a02..0000000
--- a/buildSrc-tests/src/test/kotlin/androidx/build/PublishExtensionTest.kt
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * 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 androidx.build
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-
-class PublishExtensionTest {
-
-    @Test
-    fun publishPlatformsDefault() {
-        val extension = PublishExtension()
-        assertThat(extension.publishPlatforms).isEqualTo(emptyList<String>())
-    }
-
-    @Test
-    fun publishPlatformsWithJvmAndJs() {
-        val extension = PublishExtension().apply {
-            jvm = Publish.SNAPSHOT_ONLY
-            js = Publish.SNAPSHOT_ONLY
-        }
-        assertThat(extension.publishPlatforms).isEqualTo(listOf("jvm", "js"))
-    }
-
-    @Test
-    fun publishPlatformsWithJvmAndJsBuildOnly() {
-        val extension = PublishExtension().apply {
-            jvm = Publish.SNAPSHOT_ONLY
-            js = Publish.NONE
-        }
-        assertThat(extension.publishPlatforms).isEqualTo(listOf("jvm"))
-    }
-
-    @Test
-    fun publishExtensionMultiPlatformEnabledDefault() {
-        val extension = PublishExtension()
-        assertThat(extension.shouldEnableMultiplatform()).isFalse()
-    }
-
-    @Test
-    fun publishExtensionMultiPlatformEnabledWhenNotBuilding() {
-        val extension = PublishExtension().apply {
-            jvm = Publish.UNSET
-            js = Publish.UNSET
-            mac = Publish.UNSET
-            linux = Publish.UNSET
-        }
-        assertThat(extension.shouldEnableMultiplatform()).isFalse()
-    }
-
-    @Test
-    fun publishExtensionMultiPlatformEnabledWhenBuildingAtLeastOnePlatform() {
-        val extension = PublishExtension().apply {
-            jvm = Publish.NONE
-        }
-        assertThat(extension.shouldEnableMultiplatform()).isTrue()
-    }
-
-    @Test
-    fun publishExtensionMultiPlatformEnabledWhenPublishing() {
-        val extension = PublishExtension().apply {
-            jvm = Publish.SNAPSHOT_ONLY
-            js = Publish.SNAPSHOT_ONLY
-            linux = Publish.SNAPSHOT_ONLY
-            mac = Publish.SNAPSHOT_ONLY
-        }
-        assertThat(extension.shouldEnableMultiplatform()).isTrue()
-    }
-
-    @Test
-    fun shouldPublish_whenOnlyAndroid() {
-        val extension = PublishExtension().apply {
-            android = Publish.SNAPSHOT_ONLY
-        }
-        assertThat(extension.shouldPublishAny()).isTrue()
-    }
-
-    @Test
-    fun shouldPublish_whenOnlyNonAndroid() {
-        val extension = PublishExtension().apply {
-            jvm = Publish.SNAPSHOT_ONLY
-        }
-        assertThat(extension.shouldPublishAny()).isTrue()
-    }
-
-    @Test
-    fun shouldPublish_whenNotPublishing() {
-        val extension = PublishExtension().apply {
-            android = Publish.NONE
-        }
-        assertThat(extension.shouldPublishAny()).isFalse()
-    }
-
-    @Test
-    fun shouldRelease_whenOnlyAndroid() {
-        val extension = PublishExtension().apply {
-            android = Publish.SNAPSHOT_AND_RELEASE
-        }
-        assertThat(extension.shouldReleaseAny()).isTrue()
-    }
-
-    @Test
-    fun shouldRelease_whenOnlyNonAndroid() {
-        val extension = PublishExtension().apply {
-            jvm = Publish.SNAPSHOT_AND_RELEASE
-        }
-        assertThat(extension.shouldReleaseAny()).isTrue()
-    }
-
-    @Test
-    fun shouldRelease_whenNotReleasing() {
-        val extension = PublishExtension().apply {
-            android = Publish.SNAPSHOT_ONLY
-        }
-        assertThat(extension.shouldReleaseAny()).isFalse()
-    }
-
-    @Test
-    fun isPublishConfigured_whenNotConfigured() {
-        val extension = PublishExtension()
-        assertThat(extension.isPublishConfigured()).isFalse()
-    }
-
-    @Test
-    fun isPublishConfigured_whenOnlyAndroid() {
-        val extension = PublishExtension().apply {
-            android = Publish.SNAPSHOT_ONLY
-        }
-        assertThat(extension.isPublishConfigured()).isTrue()
-    }
-
-    @Test
-    fun isPublishConfigured_whenOnlyNonAndroid() {
-        val extension = PublishExtension().apply {
-            jvm = Publish.SNAPSHOT_ONLY
-        }
-        assertThat(extension.isPublishConfigured()).isTrue()
-    }
-
-    @Test
-    fun isPublishConfigured_whenBuildOnly() {
-        val extension = PublishExtension().apply {
-            android = Publish.NONE
-        }
-        assertThat(extension.isPublishConfigured()).isTrue()
-    }
-}
\ No newline at end of file
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt
index 3babb93..ac01224 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt
@@ -171,7 +171,7 @@
         if (publish != Publish.UNSET) {
             publish.shouldPublish()
         } else if (type != LibraryType.UNSET) {
-            type.publishExtension.shouldPublishAny()
+            type.publish.shouldPublish()
         } else {
             false
         }
@@ -180,14 +180,14 @@
         if (publish != Publish.UNSET) {
             publish.shouldRelease()
         } else if (type != LibraryType.UNSET) {
-            type.publishExtension.shouldReleaseAny()
+            type.publish.shouldRelease()
         } else {
             false
         }
 
     internal fun isPublishConfigured(): Boolean = (
             publish != Publish.UNSET ||
-            type.publishExtension.isPublishConfigured()
+            type.publish != Publish.UNSET
         )
 
     /**
@@ -202,7 +202,7 @@
         set(value) {
             // don't disable multiplatform if it's already enabled, because sometimes it's enabled
             // through flags and we don't want setting `type =` to disable it accidentally.
-            if (value.publishExtension.shouldEnableMultiplatform()) {
+            if (value.shouldEnableMultiplatform()) {
                 multiplatform = true
             }
             field = value
@@ -216,13 +216,6 @@
     var bypassCoordinateValidation = false
 
     /**
-     * Which KMP platforms are published by this project, as a list of artifact suffixes or an empty
-     * list for non-KMP projects.
-     */
-    val publishPlatforms: List<String>
-        get() = type.publishExtension.publishPlatforms
-
-    /**
      * Whether this project uses KMP.
      */
     private var multiplatform: Boolean = false
@@ -255,3 +248,5 @@
     var name: String? = null
     var url: String? = null
 }
+
+private fun LibraryType.shouldEnableMultiplatform() = this is LibraryType.KmpLibrary
\ No newline at end of file
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXMultiplatformExtension.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXMultiplatformExtension.kt
index fb481768..a4a6fd6 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXMultiplatformExtension.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXMultiplatformExtension.kt
@@ -62,6 +62,19 @@
         } else { null }
     }
 
+    /**
+     * Configures all mac targets supported by AndroidX.
+     */
+    @JvmOverloads
+    fun mac(
+        block: Action<KotlinNativeTarget>? = null
+    ): List<KotlinNativeTarget> {
+        return listOfNotNull(
+            macosX64(block),
+            macosArm64(block)
+        )
+    }
+
     @JvmOverloads
     fun macosX64(
         block: Action<KotlinNativeTarget>? = null
@@ -131,6 +144,15 @@
     }
 
     @JvmOverloads
+    fun linux(
+        block: Action<KotlinNativeTarget>? = null
+    ): List<KotlinNativeTarget> {
+        return listOfNotNull(
+            linuxX64(block),
+        )
+    }
+
+    @JvmOverloads
     fun linuxX64(
         block: Action<KotlinNativeTarget>? = null
     ): KotlinNativeTargetWithHostTests? {
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/Release.kt b/buildSrc/private/src/main/kotlin/androidx/build/Release.kt
index 8a7ba98..571e78f 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/Release.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/Release.kt
@@ -346,7 +346,7 @@
         )
 
         // Add platform-specific artifacts, if necessary.
-        artifacts += availablePublishPlatforms.map { suffix ->
+        artifacts += publishPlatforms.map { suffix ->
             Artifact(
                 mavenGroup = groupString,
                 projectName = "${project.name}-$suffix",
@@ -357,12 +357,12 @@
         return artifacts
     }
 
-private val AndroidXExtension.availablePublishPlatforms: List<String>
+private val AndroidXExtension.publishPlatforms: List<String>
     get() {
         val declaredTargets = project.multiplatformExtension?.targets?.asMap?.keys?.map {
             it.lowercase()
         } ?: emptySet()
-        return publishPlatforms.intersect(declaredTargets.toSet()).toList()
+        return declaredTargets.toList()
     }
 
 /**
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/LibraryType.kt b/buildSrc/public/src/main/kotlin/androidx/build/LibraryType.kt
index f34089e..0a50e7c 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/LibraryType.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/LibraryType.kt
@@ -16,8 +16,6 @@
 
 package androidx.build
 
-import groovy.lang.Closure
-
 /**
  * LibraryType represents the purpose and type of a library, whether it is a conventional library,
  * a set of samples showing how to use a conventional library, a set of lint rules for using a
@@ -58,18 +56,11 @@
  *
  */
 sealed class LibraryType(
-    publish: Publish = Publish.NONE,
+    val publish: Publish = Publish.NONE,
     val sourceJars: Boolean = false,
     val checkApi: RunApiTasks = RunApiTasks.No("Unknown Library Type"),
-    val compilationTarget: CompilationTarget = CompilationTarget.DEVICE,
-    configurePublish: PublishExtension.() -> Unit = {
-        android = publish
-    }
+    val compilationTarget: CompilationTarget = CompilationTarget.DEVICE
 ) {
-    val publishExtension = PublishExtension().apply {
-        configurePublish()
-    }
-
     val name: String
         get() = javaClass.simpleName
 
@@ -88,18 +79,8 @@
         val ANNOTATION_PROCESSOR_UTILS = AnnotationProcessorUtils()
         val OTHER_CODE_PROCESSOR = OtherCodeProcessor()
         val IDE_PLUGIN = IdePlugin()
+        val KMP_LIBRARY = KmpLibrary()
         val UNSET = Unset()
-
-        /**
-         * groovy sugar for creating KMP library. Works reasonably well without sugar in kotlin / .kts
-         */
-        @JvmStatic
-        fun kmpLibrary(closure: Closure<PublishExtension>): KmpLibrary {
-            val library = KmpLibrary {}
-            closure.delegate = library.publishExtension
-            closure.call()
-            return library
-        }
     }
     open class PublishedLibrary : LibraryType(
         publish = Publish.SNAPSHOT_AND_RELEASE,
@@ -174,8 +155,8 @@
         // Android Studio, rather than by a client of the library, but also a host-side component.
         compilationTarget = CompilationTarget.DEVICE
     )
-    class KmpLibrary(configurePublish: PublishExtension.() -> Unit) : LibraryType(
-        configurePublish = configurePublish,
+    class KmpLibrary : LibraryType(
+        publish = Publish.SNAPSHOT_AND_RELEASE,
         sourceJars = true,
         checkApi = RunApiTasks.Yes(),
         compilationTarget = CompilationTarget.DEVICE
diff --git a/collection/collection/build.gradle b/collection/collection/build.gradle
index d388796..fa9b24f 100644
--- a/collection/collection/build.gradle
+++ b/collection/collection/build.gradle
@@ -33,9 +33,8 @@
     jvm {
         withJava()
     }
-    macosX64()
-    macosArm64()
-    linuxX64()
+    mac()
+    linux()
     ios()
 
     sourceSets {
@@ -123,13 +122,7 @@
 
 androidx {
     name = "Android Support Library collections"
-    type = LibraryType.kmpLibrary {
-        android = Publish.NONE
-        jvm = Publish.SNAPSHOT_AND_RELEASE
-        linux = Publish.SNAPSHOT_AND_RELEASE
-        mac = Publish.SNAPSHOT_AND_RELEASE
-        ios = Publish.SNAPSHOT_AND_RELEASE
-    }
+    type = LibraryType.KMP_LIBRARY
     mavenGroup = LibraryGroups.COLLECTION
     inceptionYear = "2018"
     description = "Standalone efficient collections."
diff --git a/datastore/datastore-core-okio/build.gradle b/datastore/datastore-core-okio/build.gradle
index 11f42b4..9054366 100644
--- a/datastore/datastore-core-okio/build.gradle
+++ b/datastore/datastore-core-okio/build.gradle
@@ -33,9 +33,8 @@
     jvm {
         withJava()
     }
-    macosX64()
-    linuxX64()
-    macosArm64()
+    mac()
+    linux()
     sourceSets {
         commonMain {
             dependencies {
@@ -103,12 +102,7 @@
     // temporarily disabled for parity with state prior to library type refactor b/235209373
     publish = Publish.NONE
     runApiTasks = new RunApiTasks.No("Temporarily disabled, but should be re-enabled b/235209373")
-    type = LibraryType.kmpLibrary {
-        android = Publish.NONE
-        jvm = Publish.SNAPSHOT_AND_RELEASE
-        linux = Publish.SNAPSHOT_AND_RELEASE
-        mac = Publish.SNAPSHOT_AND_RELEASE
-    }
+    type = LibraryType.KMP_LIBRARY
     mavenGroup = LibraryGroups.DATASTORE
     inceptionYear = "2020"
     description = "Android DataStore Core Okio- contains APIs to use datastore-core in multiplatform via okio"
diff --git a/datastore/datastore-core/build.gradle b/datastore/datastore-core/build.gradle
index 4355020..d6f826c 100644
--- a/datastore/datastore-core/build.gradle
+++ b/datastore/datastore-core/build.gradle
@@ -31,9 +31,8 @@
     jvm {
         withJava()
     }
-    macosX64()
-    linuxX64()
-    macosArm64()
+    mac()
+    linux()
     sourceSets {
         commonMain {
             dependencies {
@@ -104,12 +103,7 @@
 
 androidx {
     name = "Android DataStore Core"
-    type = LibraryType.kmpLibrary {
-        android = Publish.NONE
-        jvm = Publish.SNAPSHOT_AND_RELEASE
-        linux = Publish.SNAPSHOT_AND_RELEASE
-        mac = Publish.SNAPSHOT_AND_RELEASE
-    }
+    type = LibraryType.KMP_LIBRARY
     mavenGroup = LibraryGroups.DATASTORE
     inceptionYear = "2020"
     description = "Android DataStore Core - contains the underlying store used by each serialization method"