Skip to content

Commit b317c60

Browse files
[3.14] gh-142278: Add granular change detection for platforms in CI (GH-142350) (#142537)
Co-authored-by: Hugo van Kemenade <[email protected]>
1 parent 82ebdd2 commit b317c60

File tree

3 files changed

+129
-44
lines changed

3 files changed

+129
-44
lines changed

.github/workflows/build.yml

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ jobs:
238238
macOS
239239
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
240240
needs: build-context
241-
if: needs.build-context.outputs.run-tests == 'true'
241+
if: needs.build-context.outputs.run-macos == 'true'
242242
strategy:
243243
fail-fast: false
244244
matrix:
@@ -264,7 +264,7 @@ jobs:
264264
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
265265
${{ fromJSON(matrix.bolt) && '(bolt)' || '' }}
266266
needs: build-context
267-
if: needs.build-context.outputs.run-tests == 'true'
267+
if: needs.build-context.outputs.run-ubuntu == 'true'
268268
strategy:
269269
fail-fast: false
270270
matrix:
@@ -295,7 +295,7 @@ jobs:
295295
runs-on: ${{ matrix.os }}
296296
timeout-minutes: 60
297297
needs: build-context
298-
if: needs.build-context.outputs.run-tests == 'true'
298+
if: needs.build-context.outputs.run-ubuntu == 'true'
299299
strategy:
300300
fail-fast: false
301301
matrix:
@@ -349,7 +349,7 @@ jobs:
349349
build-android:
350350
name: Android (${{ matrix.arch }})
351351
needs: build-context
352-
if: needs.build-context.outputs.run-tests == 'true'
352+
if: needs.build-context.outputs.run-android == 'true'
353353
timeout-minutes: 60
354354
strategy:
355355
fail-fast: false
@@ -371,7 +371,7 @@ jobs:
371371
build-ios:
372372
name: iOS
373373
needs: build-context
374-
if: needs.build-context.outputs.run-tests == 'true'
374+
if: needs.build-context.outputs.run-ios == 'true'
375375
timeout-minutes: 60
376376
runs-on: macos-14
377377
steps:
@@ -394,15 +394,15 @@ jobs:
394394
build-wasi:
395395
name: 'WASI'
396396
needs: build-context
397-
if: needs.build-context.outputs.run-tests == 'true'
397+
if: needs.build-context.outputs.run-wasi == 'true'
398398
uses: ./.github/workflows/reusable-wasi.yml
399399

400400
test-hypothesis:
401401
name: "Hypothesis tests on Ubuntu"
402402
runs-on: ubuntu-24.04
403403
timeout-minutes: 60
404404
needs: build-context
405-
if: needs.build-context.outputs.run-tests == 'true'
405+
if: needs.build-context.outputs.run-ubuntu == 'true'
406406
env:
407407
OPENSSL_VER: 3.0.18
408408
PYTHONSTRICTEXTENSIONBUILD: 1
@@ -509,7 +509,7 @@ jobs:
509509
runs-on: ${{ matrix.os }}
510510
timeout-minutes: 60
511511
needs: build-context
512-
if: needs.build-context.outputs.run-tests == 'true'
512+
if: needs.build-context.outputs.run-ubuntu == 'true'
513513
strategy:
514514
fail-fast: false
515515
matrix:
@@ -562,7 +562,7 @@ jobs:
562562
# ${{ '' } is a hack to nest jobs under the same sidebar category.
563563
name: Sanitizers${{ '' }} # zizmor: ignore[obfuscation]
564564
needs: build-context
565-
if: needs.build-context.outputs.run-tests == 'true'
565+
if: needs.build-context.outputs.run-ubuntu == 'true'
566566
strategy:
567567
fail-fast: false
568568
matrix:
@@ -587,7 +587,7 @@ jobs:
587587
runs-on: ubuntu-latest
588588
timeout-minutes: 60
589589
needs: build-context
590-
if: needs.build-context.outputs.run-tests == 'true'
590+
if: needs.build-context.outputs.run-ubuntu == 'true'
591591
steps:
592592
- uses: actions/checkout@v4
593593
with:
@@ -691,43 +691,31 @@ jobs:
691691
test-hypothesis,
692692
cifuzz,
693693
allowed-skips: >-
694+
${{ !fromJSON(needs.build-context.outputs.run-docs) && 'check-docs,' || '' }}
694695
${{
695-
!fromJSON(needs.build-context.outputs.run-docs)
696+
needs.build-context.outputs.run-tests != 'true'
696697
&& '
697-
check-docs,
698+
check-autoconf-regen,
699+
check-generated-files,
698700
'
699701
|| ''
700702
}}
703+
${{ !fromJSON(needs.build-context.outputs.run-windows-tests) && 'build-windows,' || '' }}
704+
${{ !fromJSON(needs.build-context.outputs.run-ci-fuzz) && 'cifuzz,' || '' }}
705+
${{ !fromJSON(needs.build-context.outputs.run-macos) && 'build-macos,' || '' }}
701706
${{
702-
needs.build-context.outputs.run-tests != 'true'
707+
!fromJSON(needs.build-context.outputs.run-ubuntu)
703708
&& '
704-
check-autoconf-regen,
705-
check-generated-files,
706-
build-macos,
707709
build-ubuntu,
708710
build-ubuntu-ssltests,
709-
build-android,
710-
build-ios,
711-
build-wasi,
712711
test-hypothesis,
713712
build-asan,
714713
build-san,
715714
cross-build-linux,
716715
'
717716
|| ''
718717
}}
719-
${{
720-
!fromJSON(needs.build-context.outputs.run-windows-tests)
721-
&& '
722-
build-windows,
723-
'
724-
|| ''
725-
}}
726-
${{
727-
!fromJSON(needs.build-context.outputs.run-ci-fuzz)
728-
&& '
729-
cifuzz,
730-
'
731-
|| ''
732-
}}
718+
${{ !fromJSON(needs.build-context.outputs.run-android) && 'build-android,' || '' }}
719+
${{ !fromJSON(needs.build-context.outputs.run-ios) && 'build-ios,' || '' }}
720+
${{ !fromJSON(needs.build-context.outputs.run-wasi) && 'build-wasi,' || '' }}
733721
jobs: ${{ toJSON(needs) }}

.github/workflows/reusable-context.yml

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,51 @@ 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-ios:
30+
description: Whether to run the iOS tests
31+
value: ${{ jobs.compute-changes.outputs.run-ios }} # bool
32+
run-macos:
33+
description: Whether to run the macOS tests
34+
value: ${{ jobs.compute-changes.outputs.run-macos }} # bool
2335
run-tests:
2436
description: Whether to run the regular tests
2537
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
38+
run-ubuntu:
39+
description: Whether to run the Ubuntu tests
40+
value: ${{ jobs.compute-changes.outputs.run-ubuntu }} # bool
41+
run-wasi:
42+
description: Whether to run the WASI tests
43+
value: ${{ jobs.compute-changes.outputs.run-wasi }} # bool
2944
run-windows-msi:
3045
description: Whether to run the MSI installer smoke tests
3146
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
47+
run-windows-tests:
48+
description: Whether to run the Windows tests
49+
value: ${{ jobs.compute-changes.outputs.run-windows-tests }} # bool
3550

3651
jobs:
3752
compute-changes:
3853
name: Create context from changed files
3954
runs-on: ubuntu-latest
4055
timeout-minutes: 10
4156
outputs:
57+
run-android: ${{ steps.changes.outputs.run-android }}
4258
run-ci-fuzz: ${{ steps.changes.outputs.run-ci-fuzz }}
4359
run-docs: ${{ steps.changes.outputs.run-docs }}
60+
run-ios: ${{ steps.changes.outputs.run-ios }}
61+
run-macos: ${{ steps.changes.outputs.run-macos }}
4462
run-tests: ${{ steps.changes.outputs.run-tests }}
63+
run-ubuntu: ${{ steps.changes.outputs.run-ubuntu }}
64+
run-wasi: ${{ steps.changes.outputs.run-wasi }}
4565
run-windows-msi: ${{ steps.changes.outputs.run-windows-msi }}
4666
run-windows-tests: ${{ steps.changes.outputs.run-windows-tests }}
4767
steps:

Tools/build/compute-changes.py

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

48+
ANDROID_DIRS = frozenset({"Android"})
49+
IOS_DIRS = frozenset({"Apple", "iOS"})
50+
MACOS_DIRS = frozenset({"Mac"})
51+
WASI_DIRS = frozenset({Path("Tools", "wasm")})
52+
4853

4954
@dataclass(kw_only=True, slots=True)
5055
class Outputs:
56+
run_android: bool = False
5157
run_ci_fuzz: bool = False
5258
run_docs: bool = False
59+
run_ios: bool = False
60+
run_macos: bool = False
5361
run_tests: bool = False
62+
run_ubuntu: bool = False
63+
run_wasi: bool = False
5464
run_windows_msi: bool = False
5565
run_windows_tests: bool = False
5666

@@ -63,7 +73,15 @@ def compute_changes() -> None:
6373
outputs = process_changed_files(files)
6474
else:
6575
# Otherwise, just run the tests
66-
outputs = Outputs(run_tests=True, run_windows_tests=True)
76+
outputs = Outputs(
77+
run_android=True,
78+
run_ios=True,
79+
run_macos=True,
80+
run_tests=True,
81+
run_ubuntu=True,
82+
run_wasi=True,
83+
run_windows_tests=True,
84+
)
6785
outputs = process_target_branch(outputs, target_branch)
6886

6987
if outputs.run_tests:
@@ -111,13 +129,31 @@ def get_changed_files(
111129
return frozenset(map(Path, filter(None, map(str.strip, changed_files))))
112130

113131

132+
def get_file_platform(file: Path) -> str | None:
133+
if not file.parts:
134+
return None
135+
first_part = file.parts[0]
136+
if first_part in MACOS_DIRS:
137+
return "macos"
138+
if first_part in IOS_DIRS:
139+
return "ios"
140+
if first_part in ANDROID_DIRS:
141+
return "android"
142+
if len(file.parts) >= 2 and Path(*file.parts[:2]) in WASI_DIRS: # Tools/wasm/
143+
return "wasi"
144+
return None
145+
146+
114147
def process_changed_files(changed_files: Set[Path]) -> Outputs:
115148
run_tests = False
116149
run_ci_fuzz = False
117150
run_docs = False
118151
run_windows_tests = False
119152
run_windows_msi = False
120153

154+
platforms_changed = set()
155+
has_platform_specific_change = True
156+
121157
for file in changed_files:
122158
# Documentation files
123159
doc_or_misc = file.parts[0] in {"Doc", "Misc"}
@@ -126,10 +162,15 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
126162
if file.parent == GITHUB_WORKFLOWS_PATH:
127163
if file.name == "build.yml":
128164
run_tests = run_ci_fuzz = True
165+
has_platform_specific_change = False
129166
if file.name == "reusable-docs.yml":
130167
run_docs = True
131168
if file.name == "reusable-windows-msi.yml":
132169
run_windows_msi = True
170+
if file.name == "reusable-macos.yml":
171+
platforms_changed.add("macos")
172+
if file.name == "reusable-wasi.yml":
173+
platforms_changed.add("wasi")
133174

134175
if not (
135176
doc_file
@@ -138,8 +179,13 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
138179
):
139180
run_tests = True
140181

141-
if file not in UNIX_BUILD_SYSTEM_FILE_NAMES:
142-
run_windows_tests = True
182+
platform = get_file_platform(file)
183+
if platform is not None:
184+
platforms_changed.add(platform)
185+
else:
186+
has_platform_specific_change = False
187+
if file not in UNIX_BUILD_SYSTEM_FILE_NAMES:
188+
run_windows_tests = True
143189

144190
# The fuzz tests are pretty slow so they are executed only for PRs
145191
# changing relevant files.
@@ -159,12 +205,38 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
159205
if file.parts[:2] == ("Tools", "msi"):
160206
run_windows_msi = True
161207

208+
# Check which platform specific tests to run
209+
if run_tests:
210+
if not has_platform_specific_change or not platforms_changed:
211+
run_android = True
212+
run_ios = True
213+
run_macos = True
214+
run_ubuntu = True
215+
run_wasi = True
216+
else:
217+
run_android = "android" in platforms_changed
218+
run_ios = "ios" in platforms_changed
219+
run_macos = "macos" in platforms_changed
220+
run_ubuntu = False
221+
run_wasi = "wasi" in platforms_changed
222+
else:
223+
run_android = False
224+
run_ios = False
225+
run_macos = False
226+
run_ubuntu = False
227+
run_wasi = False
228+
162229
return Outputs(
230+
run_android=run_android,
163231
run_ci_fuzz=run_ci_fuzz,
164232
run_docs=run_docs,
233+
run_ios=run_ios,
234+
run_macos=run_macos,
165235
run_tests=run_tests,
166-
run_windows_tests=run_windows_tests,
236+
run_ubuntu=run_ubuntu,
237+
run_wasi=run_wasi,
167238
run_windows_msi=run_windows_msi,
239+
run_windows_tests=run_windows_tests,
168240
)
169241

170242

@@ -191,11 +263,16 @@ def write_github_output(outputs: Outputs) -> None:
191263
return
192264

193265
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as f:
266+
f.write(f"run-android={bool_lower(outputs.run_android)}\n")
194267
f.write(f"run-ci-fuzz={bool_lower(outputs.run_ci_fuzz)}\n")
195268
f.write(f"run-docs={bool_lower(outputs.run_docs)}\n")
269+
f.write(f"run-ios={bool_lower(outputs.run_ios)}\n")
270+
f.write(f"run-macos={bool_lower(outputs.run_macos)}\n")
196271
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")
272+
f.write(f"run-ubuntu={bool_lower(outputs.run_ubuntu)}\n")
273+
f.write(f"run-wasi={bool_lower(outputs.run_wasi)}\n")
198274
f.write(f"run-windows-msi={bool_lower(outputs.run_windows_msi)}\n")
275+
f.write(f"run-windows-tests={bool_lower(outputs.run_windows_tests)}\n")
199276

200277

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

0 commit comments

Comments
 (0)