]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-142278: Add granular change detection for platforms in CI (GH-142350) ...
authorStan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
Thu, 11 Dec 2025 16:44:05 +0000 (16:44 +0000)
committerGitHub <noreply@github.com>
Thu, 11 Dec 2025 16:44:05 +0000 (16:44 +0000)
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
.github/workflows/build.yml
.github/workflows/reusable-context.yml
Tools/build/compute-changes.py

index 04b0e23786bff8eefba841178afe81c7e1b10db8..dc5f1af4c4c21ad0d98fca9ff66501d452618bd2 100644 (file)
@@ -241,7 +241,7 @@ jobs:
       macOS
       ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
     needs: build-context
-    if: needs.build-context.outputs.run-tests == 'true'
+    if: needs.build-context.outputs.run-macos == 'true'
     strategy:
       fail-fast: false
       matrix:
@@ -266,7 +266,7 @@ jobs:
       Ubuntu
       ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
     needs: build-context
-    if: needs.build-context.outputs.run-tests == 'true'
+    if: needs.build-context.outputs.run-ubuntu == 'true'
     strategy:
       fail-fast: false
       matrix:
@@ -282,7 +282,7 @@ jobs:
     runs-on: ${{ matrix.os }}
     timeout-minutes: 60
     needs: build-context
-    if: needs.build-context.outputs.run-tests == 'true'
+    if: needs.build-context.outputs.run-ubuntu == 'true'
     strategy:
       fail-fast: false
       matrix:
@@ -335,7 +335,7 @@ jobs:
   build-android:
     name: Android (${{ matrix.arch }})
     needs: build-context
-    if: needs.build-context.outputs.run-tests == 'true'
+    if: needs.build-context.outputs.run-android == 'true'
     timeout-minutes: 60
     strategy:
       fail-fast: false
@@ -357,7 +357,7 @@ jobs:
   build-wasi:
     name: 'WASI'
     needs: build-context
-    if: needs.build-context.outputs.run-tests == 'true'
+    if: needs.build-context.outputs.run-wasi == 'true'
     uses: ./.github/workflows/reusable-wasi.yml
 
   test-hypothesis:
@@ -365,7 +365,7 @@ jobs:
     runs-on: ubuntu-24.04
     timeout-minutes: 60
     needs: build-context
-    if: needs.build-context.outputs.run-tests == 'true'
+    if: needs.build-context.outputs.run-ubuntu == 'true'
     env:
       OPENSSL_VER: 3.0.18
       PYTHONSTRICTEXTENSIONBUILD: 1
@@ -471,7 +471,7 @@ jobs:
     runs-on: ${{ matrix.os }}
     timeout-minutes: 60
     needs: build-context
-    if: needs.build-context.outputs.run-tests == 'true'
+    if: needs.build-context.outputs.run-ubuntu == 'true'
     strategy:
       fail-fast: false
       matrix:
@@ -524,7 +524,7 @@ jobs:
     # ${{ '' } is a hack to nest jobs under the same sidebar category.
     name: Sanitizers${{ '' }}  # zizmor: ignore[obfuscation]
     needs: build-context
-    if: needs.build-context.outputs.run-tests == 'true'
+    if: needs.build-context.outputs.run-ubuntu == 'true'
     strategy:
       fail-fast: false
       matrix:
@@ -612,41 +612,29 @@ jobs:
           test-hypothesis,
           cifuzz,
         allowed-skips: >-
+          ${{ !fromJSON(needs.build-context.outputs.run-docs) && 'check-docs,' || '' }}
           ${{
-            !fromJSON(needs.build-context.outputs.run-docs)
+            needs.build-context.outputs.run-tests != 'true'
             && '
-            check-docs,
+            check-autoconf-regen,
+            check-generated-files,
             '
             || ''
           }}
+          ${{ !fromJSON(needs.build-context.outputs.run-windows-tests) && 'build-windows,' || '' }}
+          ${{ !fromJSON(needs.build-context.outputs.run-ci-fuzz) && 'cifuzz,' || '' }}
+          ${{ !fromJSON(needs.build-context.outputs.run-macos) && 'build-macos,' || '' }}
           ${{
-            needs.build-context.outputs.run-tests != 'true'
+            !fromJSON(needs.build-context.outputs.run-ubuntu)
             && '
-            check-autoconf-regen,
-            check-generated-files,
-            build-macos,
             build-ubuntu,
             build-ubuntu-ssltests,
-            build-android,
-            build-wasi,
             test-hypothesis,
             build-asan,
             build-san,
             '
             || ''
           }}
-          ${{
-            !fromJSON(needs.build-context.outputs.run-windows-tests)
-            && '
-            build-windows,
-            '
-            || ''
-          }}
-          ${{
-            !fromJSON(needs.build-context.outputs.run-ci-fuzz)
-            && '
-            cifuzz,
-            '
-            || ''
-          }}
+          ${{ !fromJSON(needs.build-context.outputs.run-android) && 'build-android,' || '' }}
+          ${{ !fromJSON(needs.build-context.outputs.run-wasi) && 'build-wasi,' || '' }}
         jobs: ${{ toJSON(needs) }}
index 66c7cc47de03fb1df73d8ac8b74f15c8f633f7da..220e41c967719792ddf8a301241fea4869e07730 100644 (file)
@@ -17,21 +17,33 @@ on:  # yamllint disable-line rule:truthy
       #        || 'falsy-branch'
       #   }}
       #
+      run-android:
+        description: Whether to run the Android tests
+        value: ${{ jobs.compute-changes.outputs.run-android }}  # bool
+      run-ci-fuzz:
+        description: Whether to run the CIFuzz job
+        value: ${{ jobs.compute-changes.outputs.run-ci-fuzz }}  # bool
       run-docs:
         description: Whether to build the docs
         value: ${{ jobs.compute-changes.outputs.run-docs }}  # bool
+      run-macos:
+        description: Whether to run the macOS tests
+        value: ${{ jobs.compute-changes.outputs.run-macos }}  # bool
       run-tests:
         description: Whether to run the regular tests
         value: ${{ jobs.compute-changes.outputs.run-tests  }}  # bool
-      run-windows-tests:
-        description: Whether to run the Windows tests
-        value: ${{ jobs.compute-changes.outputs.run-windows-tests }}  # bool
+      run-ubuntu:
+        description: Whether to run the Ubuntu tests
+        value: ${{ jobs.compute-changes.outputs.run-ubuntu }}  # bool
+      run-wasi:
+        description: Whether to run the WASI tests
+        value: ${{ jobs.compute-changes.outputs.run-wasi }}  # bool
       run-windows-msi:
         description: Whether to run the MSI installer smoke tests
         value: ${{ jobs.compute-changes.outputs.run-windows-msi }}  # bool
-      run-ci-fuzz:
-        description: Whether to run the CIFuzz job
-        value: ${{ jobs.compute-changes.outputs.run-ci-fuzz }}  # bool
+      run-windows-tests:
+        description: Whether to run the Windows tests
+        value: ${{ jobs.compute-changes.outputs.run-windows-tests }}  # bool
 
 jobs:
   compute-changes:
@@ -39,9 +51,13 @@ jobs:
     runs-on: ubuntu-latest
     timeout-minutes: 10
     outputs:
+      run-android: ${{ steps.changes.outputs.run-android }}
       run-ci-fuzz: ${{ steps.changes.outputs.run-ci-fuzz }}
       run-docs: ${{ steps.changes.outputs.run-docs }}
+      run-macos: ${{ steps.changes.outputs.run-macos }}
       run-tests: ${{ steps.changes.outputs.run-tests }}
+      run-ubuntu: ${{ steps.changes.outputs.run-ubuntu }}
+      run-wasi: ${{ steps.changes.outputs.run-wasi }}
       run-windows-msi: ${{ steps.changes.outputs.run-windows-msi }}
       run-windows-tests: ${{ steps.changes.outputs.run-windows-tests }}
     steps:
index b5993d29b92972fa8c59043db434d9a4a32ca19c..db347e737f306fbb7240ec280011bc2b5fcec362 100644 (file)
@@ -45,12 +45,20 @@ UNIX_BUILD_SYSTEM_FILE_NAMES = frozenset({
 SUFFIXES_C_OR_CPP = frozenset({".c", ".h", ".cpp"})
 SUFFIXES_DOCUMENTATION = frozenset({".rst", ".md"})
 
+ANDROID_DIRS = frozenset({"Android"})
+MACOS_DIRS = frozenset({"Mac"})
+WASI_DIRS = frozenset({Path("Tools", "wasm")})
+
 
 @dataclass(kw_only=True, slots=True)
 class Outputs:
+    run_android: bool = False
     run_ci_fuzz: bool = False
     run_docs: bool = False
+    run_macos: bool = False
     run_tests: bool = False
+    run_ubuntu: bool = False
+    run_wasi: bool = False
     run_windows_msi: bool = False
     run_windows_tests: bool = False
 
@@ -63,7 +71,14 @@ def compute_changes() -> None:
         outputs = process_changed_files(files)
     else:
         # Otherwise, just run the tests
-        outputs = Outputs(run_tests=True, run_windows_tests=True)
+        outputs = Outputs(
+            run_android=True,
+            run_macos=True,
+            run_tests=True,
+            run_ubuntu=True,
+            run_wasi=True,
+            run_windows_tests=True,
+        )
     outputs = process_target_branch(outputs, target_branch)
 
     if outputs.run_tests:
@@ -111,6 +126,19 @@ def get_changed_files(
     return frozenset(map(Path, filter(None, map(str.strip, changed_files))))
 
 
+def get_file_platform(file: Path) -> str | None:
+    if not file.parts:
+        return None
+    first_part = file.parts[0]
+    if first_part in MACOS_DIRS:
+        return "macos"
+    if first_part in ANDROID_DIRS:
+        return "android"
+    if len(file.parts) >= 2 and Path(*file.parts[:2]) in WASI_DIRS: # Tools/wasm/
+        return "wasi"
+    return None
+
+
 def process_changed_files(changed_files: Set[Path]) -> Outputs:
     run_tests = False
     run_ci_fuzz = False
@@ -118,6 +146,9 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
     run_windows_tests = False
     run_windows_msi = False
 
+    platforms_changed = set()
+    has_platform_specific_change = True
+
     for file in changed_files:
         # Documentation files
         doc_or_misc = file.parts[0] in {"Doc", "Misc"}
@@ -126,10 +157,15 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
         if file.parent == GITHUB_WORKFLOWS_PATH:
             if file.name == "build.yml":
                 run_tests = run_ci_fuzz = True
+                has_platform_specific_change = False
             if file.name == "reusable-docs.yml":
                 run_docs = True
             if file.name == "reusable-windows-msi.yml":
                 run_windows_msi = True
+            if file.name == "reusable-macos.yml":
+                platforms_changed.add("macos")
+            if file.name == "reusable-wasi.yml":
+                platforms_changed.add("wasi")
 
         if not (
             doc_file
@@ -138,8 +174,13 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
         ):
             run_tests = True
 
-            if file not in UNIX_BUILD_SYSTEM_FILE_NAMES:
-                run_windows_tests = True
+            platform = get_file_platform(file)
+            if platform is not None:
+                platforms_changed.add(platform)
+            else:
+                has_platform_specific_change = False
+                if file not in UNIX_BUILD_SYSTEM_FILE_NAMES:
+                    run_windows_tests = True
 
         # The fuzz tests are pretty slow so they are executed only for PRs
         # changing relevant files.
@@ -159,12 +200,34 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
         if file.parts[:2] == ("Tools", "msi"):
             run_windows_msi = True
 
+    # Check which platform specific tests to run
+    if run_tests:
+        if not has_platform_specific_change or not platforms_changed:
+            run_android = True
+            run_macos = True
+            run_ubuntu = True
+            run_wasi = True
+        else:
+            run_android = "android" in platforms_changed
+            run_macos = "macos" in platforms_changed
+            run_ubuntu = False
+            run_wasi = "wasi" in platforms_changed
+    else:
+        run_android = False
+        run_macos = False
+        run_ubuntu = False
+        run_wasi = False
+
     return Outputs(
+        run_android=run_android,
         run_ci_fuzz=run_ci_fuzz,
         run_docs=run_docs,
+        run_macos=run_macos,
         run_tests=run_tests,
-        run_windows_tests=run_windows_tests,
+        run_ubuntu=run_ubuntu,
+        run_wasi=run_wasi,
         run_windows_msi=run_windows_msi,
+        run_windows_tests=run_windows_tests,
     )
 
 
@@ -191,11 +254,15 @@ def write_github_output(outputs: Outputs) -> None:
         return
 
     with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as f:
+        f.write(f"run-android={bool_lower(outputs.run_android)}\n")
         f.write(f"run-ci-fuzz={bool_lower(outputs.run_ci_fuzz)}\n")
         f.write(f"run-docs={bool_lower(outputs.run_docs)}\n")
+        f.write(f"run-macos={bool_lower(outputs.run_macos)}\n")
         f.write(f"run-tests={bool_lower(outputs.run_tests)}\n")
-        f.write(f"run-windows-tests={bool_lower(outputs.run_windows_tests)}\n")
+        f.write(f"run-ubuntu={bool_lower(outputs.run_ubuntu)}\n")
+        f.write(f"run-wasi={bool_lower(outputs.run_wasi)}\n")
         f.write(f"run-windows-msi={bool_lower(outputs.run_windows_msi)}\n")
+        f.write(f"run-windows-tests={bool_lower(outputs.run_windows_tests)}\n")
 
 
 def bool_lower(value: bool, /) -> str: