Skip to content

Commit 71bdb38

Browse files
[3.13] gh-142278: Add granular change detection for platforms in CI (GH-142350) (#142578)
Co-authored-by: Hugo van Kemenade <[email protected]>
1 parent fda856f commit 71bdb38

File tree

3 files changed

+112
-41
lines changed

3 files changed

+112
-41
lines changed

.github/workflows/build.yml

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ jobs:
241241
macOS
242242
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
243243
needs: build-context
244-
if: needs.build-context.outputs.run-tests == 'true'
244+
if: needs.build-context.outputs.run-macos == 'true'
245245
strategy:
246246
fail-fast: false
247247
matrix:
@@ -266,7 +266,7 @@ jobs:
266266
Ubuntu
267267
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
268268
needs: build-context
269-
if: needs.build-context.outputs.run-tests == 'true'
269+
if: needs.build-context.outputs.run-ubuntu == 'true'
270270
strategy:
271271
fail-fast: false
272272
matrix:
@@ -282,7 +282,7 @@ jobs:
282282
runs-on: ${{ matrix.os }}
283283
timeout-minutes: 60
284284
needs: build-context
285-
if: needs.build-context.outputs.run-tests == 'true'
285+
if: needs.build-context.outputs.run-ubuntu == 'true'
286286
strategy:
287287
fail-fast: false
288288
matrix:
@@ -335,7 +335,7 @@ jobs:
335335
build-android:
336336
name: Android (${{ matrix.arch }})
337337
needs: build-context
338-
if: needs.build-context.outputs.run-tests == 'true'
338+
if: needs.build-context.outputs.run-android == 'true'
339339
timeout-minutes: 60
340340
strategy:
341341
fail-fast: false
@@ -357,15 +357,15 @@ jobs:
357357
build-wasi:
358358
name: 'WASI'
359359
needs: build-context
360-
if: needs.build-context.outputs.run-tests == 'true'
360+
if: needs.build-context.outputs.run-wasi == 'true'
361361
uses: ./.github/workflows/reusable-wasi.yml
362362

363363
test-hypothesis:
364364
name: "Hypothesis tests on Ubuntu"
365365
runs-on: ubuntu-24.04
366366
timeout-minutes: 60
367367
needs: build-context
368-
if: needs.build-context.outputs.run-tests == 'true'
368+
if: needs.build-context.outputs.run-ubuntu == 'true'
369369
env:
370370
OPENSSL_VER: 3.0.18
371371
PYTHONSTRICTEXTENSIONBUILD: 1
@@ -471,7 +471,7 @@ jobs:
471471
runs-on: ${{ matrix.os }}
472472
timeout-minutes: 60
473473
needs: build-context
474-
if: needs.build-context.outputs.run-tests == 'true'
474+
if: needs.build-context.outputs.run-ubuntu == 'true'
475475
strategy:
476476
fail-fast: false
477477
matrix:
@@ -524,7 +524,7 @@ jobs:
524524
# ${{ '' } is a hack to nest jobs under the same sidebar category.
525525
name: Sanitizers${{ '' }} # zizmor: ignore[obfuscation]
526526
needs: build-context
527-
if: needs.build-context.outputs.run-tests == 'true'
527+
if: needs.build-context.outputs.run-ubuntu == 'true'
528528
strategy:
529529
fail-fast: false
530530
matrix:
@@ -612,41 +612,29 @@ jobs:
612612
test-hypothesis,
613613
cifuzz,
614614
allowed-skips: >-
615+
${{ !fromJSON(needs.build-context.outputs.run-docs) && 'check-docs,' || '' }}
615616
${{
616-
!fromJSON(needs.build-context.outputs.run-docs)
617+
needs.build-context.outputs.run-tests != 'true'
617618
&& '
618-
check-docs,
619+
check-autoconf-regen,
620+
check-generated-files,
619621
'
620622
|| ''
621623
}}
624+
${{ !fromJSON(needs.build-context.outputs.run-windows-tests) && 'build-windows,' || '' }}
625+
${{ !fromJSON(needs.build-context.outputs.run-ci-fuzz) && 'cifuzz,' || '' }}
626+
${{ !fromJSON(needs.build-context.outputs.run-macos) && 'build-macos,' || '' }}
622627
${{
623-
needs.build-context.outputs.run-tests != 'true'
628+
!fromJSON(needs.build-context.outputs.run-ubuntu)
624629
&& '
625-
check-autoconf-regen,
626-
check-generated-files,
627-
build-macos,
628630
build-ubuntu,
629631
build-ubuntu-ssltests,
630-
build-android,
631-
build-wasi,
632632
test-hypothesis,
633633
build-asan,
634634
build-san,
635635
'
636636
|| ''
637637
}}
638-
${{
639-
!fromJSON(needs.build-context.outputs.run-windows-tests)
640-
&& '
641-
build-windows,
642-
'
643-
|| ''
644-
}}
645-
${{
646-
!fromJSON(needs.build-context.outputs.run-ci-fuzz)
647-
&& '
648-
cifuzz,
649-
'
650-
|| ''
651-
}}
638+
${{ !fromJSON(needs.build-context.outputs.run-android) && 'build-android,' || '' }}
639+
${{ !fromJSON(needs.build-context.outputs.run-wasi) && 'build-wasi,' || '' }}
652640
jobs: ${{ toJSON(needs) }}

.github/workflows/reusable-context.yml

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,47 @@ on: # yamllint disable-line rule:truthy
1717
# || 'falsy-branch'
1818
# }}
1919
#
20+
run-android:
21+
description: Whether to run the Android tests
22+
value: ${{ jobs.compute-changes.outputs.run-android }} # bool
23+
run-ci-fuzz:
24+
description: Whether to run the CIFuzz job
25+
value: ${{ jobs.compute-changes.outputs.run-ci-fuzz }} # bool
2026
run-docs:
2127
description: Whether to build the docs
2228
value: ${{ jobs.compute-changes.outputs.run-docs }} # bool
29+
run-macos:
30+
description: Whether to run the macOS tests
31+
value: ${{ jobs.compute-changes.outputs.run-macos }} # bool
2332
run-tests:
2433
description: Whether to run the regular tests
2534
value: ${{ jobs.compute-changes.outputs.run-tests }} # bool
26-
run-windows-tests:
27-
description: Whether to run the Windows tests
28-
value: ${{ jobs.compute-changes.outputs.run-windows-tests }} # bool
35+
run-ubuntu:
36+
description: Whether to run the Ubuntu tests
37+
value: ${{ jobs.compute-changes.outputs.run-ubuntu }} # bool
38+
run-wasi:
39+
description: Whether to run the WASI tests
40+
value: ${{ jobs.compute-changes.outputs.run-wasi }} # bool
2941
run-windows-msi:
3042
description: Whether to run the MSI installer smoke tests
3143
value: ${{ jobs.compute-changes.outputs.run-windows-msi }} # bool
32-
run-ci-fuzz:
33-
description: Whether to run the CIFuzz job
34-
value: ${{ jobs.compute-changes.outputs.run-ci-fuzz }} # bool
44+
run-windows-tests:
45+
description: Whether to run the Windows tests
46+
value: ${{ jobs.compute-changes.outputs.run-windows-tests }} # bool
3547

3648
jobs:
3749
compute-changes:
3850
name: Create context from changed files
3951
runs-on: ubuntu-latest
4052
timeout-minutes: 10
4153
outputs:
54+
run-android: ${{ steps.changes.outputs.run-android }}
4255
run-ci-fuzz: ${{ steps.changes.outputs.run-ci-fuzz }}
4356
run-docs: ${{ steps.changes.outputs.run-docs }}
57+
run-macos: ${{ steps.changes.outputs.run-macos }}
4458
run-tests: ${{ steps.changes.outputs.run-tests }}
59+
run-ubuntu: ${{ steps.changes.outputs.run-ubuntu }}
60+
run-wasi: ${{ steps.changes.outputs.run-wasi }}
4561
run-windows-msi: ${{ steps.changes.outputs.run-windows-msi }}
4662
run-windows-tests: ${{ steps.changes.outputs.run-windows-tests }}
4763
steps:

Tools/build/compute-changes.py

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,20 @@
4545
SUFFIXES_C_OR_CPP = frozenset({".c", ".h", ".cpp"})
4646
SUFFIXES_DOCUMENTATION = frozenset({".rst", ".md"})
4747

48+
ANDROID_DIRS = frozenset({"Android"})
49+
MACOS_DIRS = frozenset({"Mac"})
50+
WASI_DIRS = frozenset({Path("Tools", "wasm")})
51+
4852

4953
@dataclass(kw_only=True, slots=True)
5054
class Outputs:
55+
run_android: bool = False
5156
run_ci_fuzz: bool = False
5257
run_docs: bool = False
58+
run_macos: bool = False
5359
run_tests: bool = False
60+
run_ubuntu: bool = False
61+
run_wasi: bool = False
5462
run_windows_msi: bool = False
5563
run_windows_tests: bool = False
5664

@@ -63,7 +71,14 @@ def compute_changes() -> None:
6371
outputs = process_changed_files(files)
6472
else:
6573
# Otherwise, just run the tests
66-
outputs = Outputs(run_tests=True, run_windows_tests=True)
74+
outputs = Outputs(
75+
run_android=True,
76+
run_macos=True,
77+
run_tests=True,
78+
run_ubuntu=True,
79+
run_wasi=True,
80+
run_windows_tests=True,
81+
)
6782
outputs = process_target_branch(outputs, target_branch)
6883

6984
if outputs.run_tests:
@@ -111,13 +126,29 @@ def get_changed_files(
111126
return frozenset(map(Path, filter(None, map(str.strip, changed_files))))
112127

113128

129+
def get_file_platform(file: Path) -> str | None:
130+
if not file.parts:
131+
return None
132+
first_part = file.parts[0]
133+
if first_part in MACOS_DIRS:
134+
return "macos"
135+
if first_part in ANDROID_DIRS:
136+
return "android"
137+
if len(file.parts) >= 2 and Path(*file.parts[:2]) in WASI_DIRS: # Tools/wasm/
138+
return "wasi"
139+
return None
140+
141+
114142
def process_changed_files(changed_files: Set[Path]) -> Outputs:
115143
run_tests = False
116144
run_ci_fuzz = False
117145
run_docs = False
118146
run_windows_tests = False
119147
run_windows_msi = False
120148

149+
platforms_changed = set()
150+
has_platform_specific_change = True
151+
121152
for file in changed_files:
122153
# Documentation files
123154
doc_or_misc = file.parts[0] in {"Doc", "Misc"}
@@ -126,10 +157,15 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
126157
if file.parent == GITHUB_WORKFLOWS_PATH:
127158
if file.name == "build.yml":
128159
run_tests = run_ci_fuzz = True
160+
has_platform_specific_change = False
129161
if file.name == "reusable-docs.yml":
130162
run_docs = True
131163
if file.name == "reusable-windows-msi.yml":
132164
run_windows_msi = True
165+
if file.name == "reusable-macos.yml":
166+
platforms_changed.add("macos")
167+
if file.name == "reusable-wasi.yml":
168+
platforms_changed.add("wasi")
133169

134170
if not (
135171
doc_file
@@ -138,8 +174,13 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
138174
):
139175
run_tests = True
140176

141-
if file not in UNIX_BUILD_SYSTEM_FILE_NAMES:
142-
run_windows_tests = True
177+
platform = get_file_platform(file)
178+
if platform is not None:
179+
platforms_changed.add(platform)
180+
else:
181+
has_platform_specific_change = False
182+
if file not in UNIX_BUILD_SYSTEM_FILE_NAMES:
183+
run_windows_tests = True
143184

144185
# The fuzz tests are pretty slow so they are executed only for PRs
145186
# changing relevant files.
@@ -159,12 +200,34 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
159200
if file.parts[:2] == ("Tools", "msi"):
160201
run_windows_msi = True
161202

203+
# Check which platform specific tests to run
204+
if run_tests:
205+
if not has_platform_specific_change or not platforms_changed:
206+
run_android = True
207+
run_macos = True
208+
run_ubuntu = True
209+
run_wasi = True
210+
else:
211+
run_android = "android" in platforms_changed
212+
run_macos = "macos" in platforms_changed
213+
run_ubuntu = False
214+
run_wasi = "wasi" in platforms_changed
215+
else:
216+
run_android = False
217+
run_macos = False
218+
run_ubuntu = False
219+
run_wasi = False
220+
162221
return Outputs(
222+
run_android=run_android,
163223
run_ci_fuzz=run_ci_fuzz,
164224
run_docs=run_docs,
225+
run_macos=run_macos,
165226
run_tests=run_tests,
166-
run_windows_tests=run_windows_tests,
227+
run_ubuntu=run_ubuntu,
228+
run_wasi=run_wasi,
167229
run_windows_msi=run_windows_msi,
230+
run_windows_tests=run_windows_tests,
168231
)
169232

170233

@@ -191,11 +254,15 @@ def write_github_output(outputs: Outputs) -> None:
191254
return
192255

193256
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as f:
257+
f.write(f"run-android={bool_lower(outputs.run_android)}\n")
194258
f.write(f"run-ci-fuzz={bool_lower(outputs.run_ci_fuzz)}\n")
195259
f.write(f"run-docs={bool_lower(outputs.run_docs)}\n")
260+
f.write(f"run-macos={bool_lower(outputs.run_macos)}\n")
196261
f.write(f"run-tests={bool_lower(outputs.run_tests)}\n")
197-
f.write(f"run-windows-tests={bool_lower(outputs.run_windows_tests)}\n")
262+
f.write(f"run-ubuntu={bool_lower(outputs.run_ubuntu)}\n")
263+
f.write(f"run-wasi={bool_lower(outputs.run_wasi)}\n")
198264
f.write(f"run-windows-msi={bool_lower(outputs.run_windows_msi)}\n")
265+
f.write(f"run-windows-tests={bool_lower(outputs.run_windows_tests)}\n")
199266

200267

201268
def bool_lower(value: bool, /) -> str:

0 commit comments

Comments
 (0)