Skip to content

Commit ec55e88

Browse files
authored
Generate CI runners for build matrix dynamically (#483)
1 parent 3c4fe23 commit ec55e88

File tree

5 files changed

+88
-5
lines changed

5 files changed

+88
-5
lines changed

.github/workflows/linux.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ jobs:
168168
- generate-matrix
169169
- pythonbuild
170170
- image
171-
runs-on: depot-ubuntu-22.04
171+
runs-on: ${{ matrix.runner }}
172172
strategy:
173173
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
174174
fail-fast: false

.github/workflows/macos.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ jobs:
9090
strategy:
9191
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
9292
fail-fast: false
93-
runs-on: depot-macos-latest
93+
runs-on: ${{ matrix.runner }}
9494
name: ${{ matrix.target_triple }} / ${{ matrix.python }} / ${{ matrix.build_options }}
9595
steps:
9696
- uses: actions/checkout@v4

.github/workflows/windows.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ jobs:
8888
needs:
8989
- generate-matrix
9090
- pythonbuild
91-
runs-on: windows-latest-large
91+
runs-on: ${{ matrix.runner }}
9292
strategy:
9393
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
9494
fail-fast: false

ci-matrix.py

+48-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from packaging.version import Version
1515

1616
CI_TARGETS_YAML = "ci-targets.yaml"
17+
CI_RUNNERS_YAML = "ci-runners.yaml"
1718
CI_EXTRA_SKIP_LABELS = ["documentation"]
1819

1920

@@ -88,6 +89,7 @@ def should_include_entry(entry: dict[str, str], filters: dict[str, set[str]]) ->
8889

8990
def generate_matrix_entries(
9091
config: dict[str, Any],
92+
runners: dict[str, Any],
9193
platform_filter: Optional[str] = None,
9294
label_filters: Optional[dict[str, set[str]]] = None,
9395
) -> list[dict[str, str]]:
@@ -103,6 +105,7 @@ def generate_matrix_entries(
103105
target_triple,
104106
target_config,
105107
platform,
108+
runners,
106109
label_filters.get("directives", set()),
107110
)
108111

@@ -117,22 +120,50 @@ def generate_matrix_entries(
117120
return matrix_entries
118121

119122

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+
120145
def add_matrix_entries_for_config(
121146
matrix_entries: list[dict[str, str]],
122147
target_triple: str,
123148
config: dict[str, Any],
124149
platform: str,
150+
runners: dict[str, Any],
125151
directives: set[str],
126152
) -> None:
127153
python_versions = config["python_versions"]
128154
build_options = config["build_options"]
129155
arch = config["arch"]
156+
runner = find_runner(runners, platform, arch)
130157

131158
# Create base entry that will be used for all variants
132159
base_entry = {
133160
"arch": arch,
134161
"target_triple": target_triple,
135162
"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(),
136167
}
137168

138169
# Add optional fields if they exist
@@ -142,8 +173,6 @@ def add_matrix_entries_for_config(
142173
base_entry["libc"] = config["libc"]
143174
if "vcvars" in config:
144175
base_entry["vcvars"] = config["vcvars"]
145-
if "run" in config:
146-
base_entry["run"] = str(config["run"]).lower()
147176

148177
if "dry-run" in directives:
149178
base_entry["dry-run"] = "true"
@@ -191,6 +220,11 @@ def parse_args() -> argparse.Namespace:
191220
"--labels",
192221
help="Comma-separated list of labels to filter by (e.g., 'platform:darwin,python:3.13,build:debug'), all must match.",
193222
)
223+
parser.add_argument(
224+
"--free-runners",
225+
action="store_true",
226+
help="If only free runners should be used.",
227+
)
194228
return parser.parse_args()
195229

196230

@@ -201,9 +235,21 @@ def main() -> None:
201235
with open(CI_TARGETS_YAML, "r") as f:
202236
config = yaml.safe_load(f)
203237

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+
204249
matrix = {
205250
"include": generate_matrix_entries(
206251
config,
252+
runners,
207253
args.platform,
208254
labels,
209255
)

ci-runners.yaml

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Describes the runners that the CI system can use
2+
3+
depot-ubuntu-22.04:
4+
arch: x86_64
5+
platform: linux
6+
free: false
7+
8+
# TODO: Enable this runner to perform native builds for aarch64
9+
# depot-ubuntu-22.04-arm:
10+
# arch: aarch64
11+
# platform: linux
12+
# free: false
13+
14+
depot-macos-latest:
15+
arch: x86_64
16+
platform: darwin
17+
free: false
18+
19+
ubuntu-latest:
20+
arch: x86_64
21+
platform: linux
22+
free: true
23+
24+
macos-latest:
25+
arch: x86_64
26+
platform: darwin
27+
free: true
28+
29+
windows-latest-large:
30+
arch: x86_64
31+
platform: windows
32+
free: false
33+
34+
windows-latest:
35+
arch: x86_64
36+
platform: windows
37+
free: true

0 commit comments

Comments
 (0)