Skip to content

Commit 3ae56f5

Browse files
committed
test different partition strategy
1 parent 3f70630 commit 3ae56f5

File tree

2 files changed

+59
-8
lines changed

2 files changed

+59
-8
lines changed

.github/workflows/build-common.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ jobs:
256256
- 1
257257
- 2
258258
- 3
259+
- 4
260+
- 5
259261
test-indy:
260262
- false
261263
- true

build.gradle.kts

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)