|
18 | 18 | import math |
19 | 19 | import sys |
20 | 20 |
|
| 21 | +# Define set of long-running unit tests to run in isolated shard |
| 22 | +ISOLATED_PACKAGES = { |
| 23 | + "google-cloud-compute", |
| 24 | + "google-cloud-compute-v1beta", |
| 25 | + "google-cloud-dialogflow", |
| 26 | + "google-cloud-dialogflow-cx", |
| 27 | + "google-cloud-retail", |
| 28 | +} |
| 29 | + |
| 30 | + |
21 | 31 | def get_packages(): |
22 | 32 | subdirs = ['packages'] |
23 | 33 | packages = [] |
@@ -60,50 +70,83 @@ def get_packages_to_test(): |
60 | 70 |
|
61 | 71 | return to_test |
62 | 72 |
|
| 73 | + |
63 | 74 | def group_packages(packages): |
64 | 75 | if not packages: |
65 | 76 | return [] |
66 | 77 |
|
67 | | - num_packages = len(packages) |
68 | | - |
69 | | - # 1. Only shard if > 10 packages are being touched |
70 | | - # 2. Only add a new shard if any shard would have > 10 packages. |
71 | | - # To guarantee that no shard contains more than 10 packages (when distributed evenly), |
72 | | - # we need S >= N / 10, which means S = ceil(N / 10). |
73 | | - num_shards = math.ceil(num_packages / 10) |
74 | | - |
75 | | - # Ensure at least 1 shard if we have packages |
76 | | - num_shards = max(1, num_shards) |
| 78 | + isolated_to_test = [] |
| 79 | + normal_to_test = [] |
77 | 80 |
|
78 | | - # 3. Top out at 16 shards |
79 | | - num_shards = min(16, num_shards) |
80 | | - |
81 | | - # Distribute packages between them as evenly as possible |
82 | | - shard_size = math.ceil(num_packages / num_shards) |
| 81 | + for pkg in packages: |
| 82 | + pkg_name = pkg.strip('/').split('/')[-1] |
| 83 | + if pkg_name in ISOLATED_PACKAGES: |
| 84 | + isolated_to_test.append(pkg) |
| 85 | + else: |
| 86 | + normal_to_test.append(pkg) |
83 | 87 |
|
84 | 88 | shards = [] |
85 | | - for i in range(num_shards): |
86 | | - start = i * shard_size |
87 | | - end = min((i + 1) * shard_size, num_packages) |
88 | | - if start >= num_packages: |
89 | | - break |
90 | | - shard_packages = packages[start:end] |
91 | | - index = i + 1 |
92 | | - name = f"Shard {index}" |
93 | | - num_in_shard = len(shard_packages) |
94 | | - # Calculate a descriptive range for step visibility |
95 | | - if len(shard_packages) == 1: |
96 | | - desc = shard_packages[0].strip('/').split('/')[-1] |
97 | | - else: |
98 | | - desc = f"{shard_packages[0].strip('/').split('/')[-1]}...{shard_packages[-1].strip('/').split('/')[-1]} ({num_in_shard} packages)" |
| 89 | + index = 1 |
99 | 90 |
|
| 91 | + # Add isolated packages to their own shards |
| 92 | + for pkg in isolated_to_test: |
| 93 | + pkg_name = pkg.strip('/').split('/')[-1] |
| 94 | + clean_name = pkg_name.replace("google-cloud-", "") |
100 | 95 | shards.append({ |
101 | | - "name": name, |
| 96 | + "name": clean_name, |
102 | 97 | "index": index, |
103 | | - "description": desc, |
104 | | - "packages": " ".join(shard_packages), |
105 | | - "is_sharded": num_shards > 1 |
| 98 | + "description": pkg_name, |
| 99 | + "packages": pkg, |
| 100 | + "is_sharded": True |
106 | 101 | }) |
| 102 | + index += 1 |
| 103 | + |
| 104 | + # Group the remaining packages |
| 105 | + if normal_to_test: |
| 106 | + num_packages = len(normal_to_test) |
| 107 | + |
| 108 | + # 1. Only shard if > 10 packages are being touched |
| 109 | + # 2. Only add a new shard if any shard would have > 10 packages. |
| 110 | + # To guarantee that no shard contains more than 10 packages (when distributed evenly), |
| 111 | + # we need S >= N / 10, which means S = ceil(N / 10). |
| 112 | + num_shards = math.ceil(num_packages / 10) |
| 113 | + |
| 114 | + # Ensure at least 1 shard if we have packages |
| 115 | + num_shards = max(1, num_shards) |
| 116 | + |
| 117 | + # 3. Top out at 16 shards |
| 118 | + num_shards = min(16, num_shards) |
| 119 | + |
| 120 | + # Distribute packages between them as evenly as possible |
| 121 | + shard_size = math.ceil(num_packages / num_shards) |
| 122 | + |
| 123 | + for i in range(num_shards): |
| 124 | + start = i * shard_size |
| 125 | + end = min((i + 1) * shard_size, num_packages) |
| 126 | + if start >= num_packages: |
| 127 | + break |
| 128 | + shard_packages = normal_to_test[start:end] |
| 129 | + name = f"Shard {index}" |
| 130 | + num_in_shard = len(shard_packages) |
| 131 | + if len(shard_packages) == 1: |
| 132 | + desc = shard_packages[0].strip('/').split('/')[-1] |
| 133 | + else: |
| 134 | + desc = f"{shard_packages[0].strip('/').split('/')[-1]}...{shard_packages[-1].strip('/').split('/')[-1]} ({num_in_shard} packages)" |
| 135 | + |
| 136 | + shards.append({ |
| 137 | + "name": name, |
| 138 | + "index": index, |
| 139 | + "description": desc, |
| 140 | + "packages": " ".join(shard_packages), |
| 141 | + "is_sharded": True |
| 142 | + }) |
| 143 | + index += 1 |
| 144 | + |
| 145 | + # Set is_sharded dynamically based on the total number of shards |
| 146 | + total_shards = len(shards) |
| 147 | + for shard in shards: |
| 148 | + shard["is_sharded"] = total_shards > 1 |
| 149 | + |
107 | 150 | return shards |
108 | 151 |
|
109 | 152 | if __name__ == "__main__": |
|
0 commit comments