@@ -68,22 +68,71 @@ if (gradle.startParameter.taskNames.contains("listTestsInPartition")) {
6868 group = " Help"
6969 description = " List test tasks in given partition"
7070
71- // total of 4 partitions (see modulo 4 below)
71+ // total of 6 partitions (see modulo 6 below)
7272 var testPartition = (project.findProperty(" testPartition" ) as String? )?.toInt()
7373 if (testPartition == null ) {
7474 throw GradleException (" Test partition must be specified" )
75- } else if (testPartition < 0 || testPartition >= 4 ) {
75+ } else if (testPartition < 0 || testPartition >= 6 ) {
7676 throw GradleException (" Invalid test partition" )
7777 }
7878
79+ val totalPartitions = 6
80+
81+ // Helper function to extract group name from project path
82+ fun getGroupName (projectPath : String , projectName : String ): String {
83+ val pathSegments = projectPath.split(" :" )
84+ return if (pathSegments.contains(" instrumentation" ) && pathSegments.size > 2 ) {
85+ val instrumentationIndex = pathSegments.indexOf(" instrumentation" )
86+ pathSegments.getOrNull(instrumentationIndex + 1 ) ? : projectName
87+ } else {
88+ pathSegments.getOrNull(1 ) ? : projectName
89+ }
90+ }
91+
92+ // First pass: count tasks per subproject and determine groups
93+ data class SubprojectInfo (val project : Project , val groupName : String , val taskCount : Int )
94+ val subprojectInfos = mutableListOf<SubprojectInfo >()
95+
96+ subprojects {
97+ val groupName = getGroupName(path, name)
98+ // Force task realization to get accurate count
99+ val testTasks = tasks.withType(Test ::class .java)
100+ val taskCount = testTasks.size
101+ subprojectInfos.add(SubprojectInfo (this , groupName, taskCount))
102+ }
103+
104+ // Sort by group name to keep related modules together
105+ subprojectInfos.sortBy { it.groupName }
106+
107+ // Calculate target tasks per partition
108+ val totalTasks = subprojectInfos.sumOf { it.taskCount }
109+ val targetTasksPerPartition = (totalTasks + totalPartitions - 1 ) / totalPartitions
110+
111+ // Second pass: assign subprojects to partitions using bin-packing
112+ val subprojectPartitions = mutableMapOf<String , Int >()
113+ val partitionTaskCounts = IntArray (totalPartitions)
114+ var currentPartition = 0
115+ var lastGroupName = " "
116+
117+ subprojectInfos.forEach { info ->
118+ // If we've switched to a new group and current partition has exceeded target,
119+ // move to next partition (unless we're on the last partition)
120+ if (info.groupName != lastGroupName &&
121+ partitionTaskCounts[currentPartition] >= targetTasksPerPartition &&
122+ currentPartition < totalPartitions - 1 ) {
123+ currentPartition++
124+ }
125+ lastGroupName = info.groupName
126+
127+ subprojectPartitions[info.project.path] = currentPartition
128+ partitionTaskCounts[currentPartition] + = info.taskCount
129+ }
130+
131+ // Third pass: collect tasks for the requested partition
79132 val partitionTasks = ArrayList <Test >()
80- var testPartitionCounter = 0
81133 subprojects {
82- // relying on predictable ordering of subprojects
83- // (see https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#N14CB4)
84- // since we are splitting these tasks across different github action jobs
85- val enabled = testPartitionCounter++ % 4 == testPartition
86- if (enabled) {
134+ val assignedPartition = subprojectPartitions[path]
135+ if (assignedPartition == testPartition) {
87136 tasks.withType<Test >().configureEach {
88137 partitionTasks.add(this )
89138 }
0 commit comments