Merge "Allow staging migration as independent CLs using property prefixes" into androidx-main
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
index b60e69f..962c086 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
@@ -191,12 +191,15 @@
     XCODEGEN_DOWNLOAD_URI,
     ALLOW_CUSTOM_COMPILE_SDK,
     UPDATE_SIGNATURES,
-    SUPPRESS_COMPATIBILITY_OPT_OUT,
-    SUPPRESS_COMPATIBILITY_OPT_IN,
     FilteredAnchorTask.PROP_TASK_NAME,
     FilteredAnchorTask.PROP_PATH_PREFIX,
 )
 
+val PREFIXED_ANDROIDX_PROPERTIES = setOf(
+    SUPPRESS_COMPATIBILITY_OPT_OUT,
+    SUPPRESS_COMPATIBILITY_OPT_IN,
+)
+
 /**
  * Whether to enable constraints for projects in same-version groups
  * See the property definition for more details
@@ -231,7 +234,8 @@
 fun Project.validateAllAndroidxArgumentsAreRecognized() {
     for (propertyName in project.properties.keys) {
         if (propertyName.startsWith("androidx")) {
-            if (!ALL_ANDROIDX_PROPERTIES.contains(propertyName)) {
+            if (!ALL_ANDROIDX_PROPERTIES.contains(propertyName) &&
+                PREFIXED_ANDROIDX_PROPERTIES.none { propertyName.startsWith(it) }) {
                 val message = "Unrecognized Androidx property '$propertyName'.\n" +
                     "\n" +
                     "Is this a misspelling? All recognized Androidx properties:\n" +
@@ -306,10 +310,19 @@
  * List of project path prefixes which have been opted-in to the Suppress Compatibility migration.
  */
 fun Project.getSuppressCompatibilityOptInPathPrefixes(): List<String> =
-    (findProperty(SUPPRESS_COMPATIBILITY_OPT_IN) as? String)?.split(",") ?: emptyList()
+    aggregatePropertyPrefix(SUPPRESS_COMPATIBILITY_OPT_IN)
 
 /**
  * List of project path prefixes which have been opted out of the Suppress Compatibility migration.
  */
 fun Project.getSuppressCompatibilityOptOutPathPrefixes(): List<String> =
-    (findProperty(SUPPRESS_COMPATIBILITY_OPT_OUT) as? String)?.split(",") ?: emptyList()
+    aggregatePropertyPrefix(SUPPRESS_COMPATIBILITY_OPT_OUT)
+
+internal fun Project.aggregatePropertyPrefix(prefix: String): List<String> =
+    properties.flatMap { (name, value) ->
+        if (name.startsWith(prefix)) {
+            (value as? String)?.split(",") ?: emptyList()
+        } else {
+            emptyList()
+        }
+    }
diff --git a/gradle.properties b/gradle.properties
index 327e1ab..a57ce02 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -35,8 +35,26 @@
 
 # Comma-delimited lists of project path prefixes which have been opted-out of or opted-in to the
 # Suppress Compatibility migration. Opt-out is matched first.
-androidx.suppress.compatibility.optout=activity/activity/,appsearch/appsearch-builtin-types/,appsearch/appsearch/,compose/,core/core/,core/core-telecom/,credentials/credentials/,navigation/navigation-ui/,wear/watchface/watchface-client/,window/window-java/,window/window/,graphics/graphics-path/,appsearch/appsearch-play/,work/work-datatransfer/,wear/compose/compose-foundation/,wear/protolayout/protolayout-expression/,wear/protolayout/protolayout-material/,graphics/graphics-core/
-androidx.suppress.compatibility.optin=a,b,c,d,e,f,g
+
+# First stage of Suppress Compatibility migration.
+androidx.suppress.compatibility.optout.abc=activity/activity/,appsearch/appsearch/,appsearch/appsearch-builtin-types/,appsearch/appsearch-play/,compose/,core/core/,core/core-telecom/,credentials/credentials/
+androidx.suppress.compatibility.optin.abc=a,b,c
+
+# Second stage of Suppress Compatibility migration
+androidx.suppress.compatibility.optout.defg=graphics/graphics-path/,graphics/graphics-core/
+androidx.suppress.compatibility.optin.defg=d,e,f,g
+
+# Third stage of Suppress Compatibility migration
+# androidx.suppress.compatibility.optout.hijklm=
+# androidx.suppress.compatibility.optin.hijklm=h,i,j,k,l,m
+
+# Fourth stage of Suppress Compatibility migration
+androidx.suppress.compatibility.optout.nopqrst=navigation/navigation-ui/
+# androidx.suppress.compatibility.optin.nopqrst=n,o,p,q,r,s,t
+
+# Fifth stage of Suppress Compatibility migration
+androidx.suppress.compatibility.optout.uvwxyz=wear/compose/compose-foundation/,wear/protolayout/protolayout-expression/,wear/protolayout/protolayout-material/,wear/watchface/watchface-client/,window/window/,window/window-java/,work/work-datatransfer/
+# androidx.suppress.compatibility.optin.uvwxyz=u,v,w,x,y,z
 
 # Don't warn about needing to update AGP
 android.suppressUnsupportedCompileSdk=UpsideDownCake,VanillaIceCream,33
diff --git a/playground-common/androidx-shared.properties b/playground-common/androidx-shared.properties
index 37e503a..46a9e68 100644
--- a/playground-common/androidx-shared.properties
+++ b/playground-common/androidx-shared.properties
@@ -48,8 +48,26 @@
 
 # Comma-delimited lists of project path prefixes which have been opted-out of or opted-in to the
 # Suppress Compatibility migration. Opt-out is matched first.
-androidx.suppress.compatibility.optout=activity/activity/,appsearch/appsearch-builtin-types/,appsearch/appsearch/,compose/,core/core/,core/core-telecom/,credentials/credentials/,navigation/navigation-ui/,wear/watchface/watchface-client/,window/window-java/,window/window/,graphics/graphics-path/,appsearch/appsearch-play/,work/work-datatransfer/,wear/compose/compose-foundation/,wear/protolayout/protolayout-expression/,wear/protolayout/protolayout-material/,graphics/graphics-core/
-androidx.suppress.compatibility.optin=a,b,c,d,e,f,g
+
+# First stage of Suppress Compatibility migration.
+androidx.suppress.compatibility.optout.abc=activity/activity/,appsearch/appsearch/,appsearch/appsearch-builtin-types/,appsearch/appsearch-play/,compose/,core/core/,core/core-telecom/,credentials/credentials/
+androidx.suppress.compatibility.optin.abc=a,b,c
+
+# Second stage of Suppress Compatibility migration
+androidx.suppress.compatibility.optout.defg=graphics/graphics-path/,graphics/graphics-core/
+androidx.suppress.compatibility.optin.defg=d,e,f,g
+
+# Third stage of Suppress Compatibility migration
+# androidx.suppress.compatibility.optout.hijklm=
+# androidx.suppress.compatibility.optin.hijklm=h,i,j,k,l,m
+
+# Fourth stage of Suppress Compatibility migration
+androidx.suppress.compatibility.optout.nopqrst=navigation/navigation-ui/
+# androidx.suppress.compatibility.optin.nopqrst=n,o,p,q,r,s,t
+
+# Fifth stage of Suppress Compatibility migration
+androidx.suppress.compatibility.optout.uvwxyz=wear/compose/compose-foundation/,wear/protolayout/protolayout-expression/,wear/protolayout/protolayout-material/,wear/watchface/watchface-client/,window/window/,window/window-java/,work/work-datatransfer/
+# androidx.suppress.compatibility.optin.uvwxyz=u,v,w,x,y,z
 
 # Disable features we do not use
 android.defaults.buildfeatures.aidl=false