14
14
from packaging .version import Version
15
15
16
16
CI_TARGETS_YAML = "ci-targets.yaml"
17
+ CI_RUNNERS_YAML = "ci-runners.yaml"
17
18
CI_EXTRA_SKIP_LABELS = ["documentation" ]
18
19
19
20
@@ -88,6 +89,7 @@ def should_include_entry(entry: dict[str, str], filters: dict[str, set[str]]) ->
88
89
89
90
def generate_matrix_entries (
90
91
config : dict [str , Any ],
92
+ runners : dict [str , Any ],
91
93
platform_filter : Optional [str ] = None ,
92
94
label_filters : Optional [dict [str , set [str ]]] = None ,
93
95
) -> list [dict [str , str ]]:
@@ -103,6 +105,7 @@ def generate_matrix_entries(
103
105
target_triple ,
104
106
target_config ,
105
107
platform ,
108
+ runners ,
106
109
label_filters .get ("directives" , set ()),
107
110
)
108
111
@@ -117,22 +120,50 @@ def generate_matrix_entries(
117
120
return matrix_entries
118
121
119
122
123
+ def find_runner (runners : dict [str , Any ], platform : str , arch : str ) -> str :
124
+ # Find a matching platform first
125
+ match_platform = [
126
+ runner for runner in runners if runners [runner ]["platform" ] == platform
127
+ ]
128
+
129
+ # Then, find a matching architecture
130
+ match_arch = [
131
+ runner for runner in match_platform if runners [runner ]["arch" ] == arch
132
+ ]
133
+
134
+ # If there's a matching architecture, use that
135
+ if match_arch :
136
+ return match_arch [0 ]
137
+
138
+ # Otherwise, use the first with a matching platform
139
+ if match_platform :
140
+ return match_platform [0 ]
141
+
142
+ raise RuntimeError (f"No runner found for platform { platform !r} and arch { arch !r} " )
143
+
144
+
120
145
def add_matrix_entries_for_config (
121
146
matrix_entries : list [dict [str , str ]],
122
147
target_triple : str ,
123
148
config : dict [str , Any ],
124
149
platform : str ,
150
+ runners : dict [str , Any ],
125
151
directives : set [str ],
126
152
) -> None :
127
153
python_versions = config ["python_versions" ]
128
154
build_options = config ["build_options" ]
129
155
arch = config ["arch" ]
156
+ runner = find_runner (runners , platform , arch )
130
157
131
158
# Create base entry that will be used for all variants
132
159
base_entry = {
133
160
"arch" : arch ,
134
161
"target_triple" : target_triple ,
135
162
"platform" : platform ,
163
+ "runner" : runner ,
164
+ # If `run` is in the config, use that — otherwise, default to if the
165
+ # runner architecture matches the build architecture
166
+ "run" : str (config .get ("run" , runners [runner ]["arch" ] == arch )).lower (),
136
167
}
137
168
138
169
# Add optional fields if they exist
@@ -142,8 +173,6 @@ def add_matrix_entries_for_config(
142
173
base_entry ["libc" ] = config ["libc" ]
143
174
if "vcvars" in config :
144
175
base_entry ["vcvars" ] = config ["vcvars" ]
145
- if "run" in config :
146
- base_entry ["run" ] = str (config ["run" ]).lower ()
147
176
148
177
if "dry-run" in directives :
149
178
base_entry ["dry-run" ] = "true"
@@ -191,6 +220,11 @@ def parse_args() -> argparse.Namespace:
191
220
"--labels" ,
192
221
help = "Comma-separated list of labels to filter by (e.g., 'platform:darwin,python:3.13,build:debug'), all must match." ,
193
222
)
223
+ parser .add_argument (
224
+ "--free-runners" ,
225
+ action = "store_true" ,
226
+ help = "If only free runners should be used." ,
227
+ )
194
228
return parser .parse_args ()
195
229
196
230
@@ -201,9 +235,21 @@ def main() -> None:
201
235
with open (CI_TARGETS_YAML , "r" ) as f :
202
236
config = yaml .safe_load (f )
203
237
238
+ with open (CI_RUNNERS_YAML , "r" ) as f :
239
+ runners = yaml .safe_load (f )
240
+
241
+ # If only free runners are allowed, reduce to a subset
242
+ if args .free_runners :
243
+ runners = {
244
+ runner : runner_config
245
+ for runner , runner_config in runners .items ()
246
+ if runner_config .get ("free" )
247
+ }
248
+
204
249
matrix = {
205
250
"include" : generate_matrix_entries (
206
251
config ,
252
+ runners ,
207
253
args .platform ,
208
254
labels ,
209
255
)
0 commit comments