Skip to content

Commit cd88fe4

Browse files
committed
ci: Skip testing libm in PRs if it did not change
Many contributions to compiler-builtins don't have any need to touch libm, and could get by with the few minutes of CI for compiler-builtins rather than the ~30 minutes for libm. We already have some scripts that handle changed file detection, so expand its use to skip libm CI if it doesn't need to run.
1 parent a98e933 commit cd88fe4

File tree

3 files changed

+62
-34
lines changed

3 files changed

+62
-34
lines changed

.github/workflows/main.yaml

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,27 @@ env:
1616
BENCHMARK_RUSTC: nightly-2025-01-16 # Pin the toolchain for reproducable results
1717

1818
jobs:
19+
# Determine which tests should be run based on changed files.
20+
calculate_vars:
21+
name: Calculate workflow variables
22+
runs-on: ubuntu-24.04
23+
timeout-minutes: 10
24+
env:
25+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26+
PR_NUMBER: ${{ github.event.pull_request.number }}
27+
outputs:
28+
extensive_matrix: ${{ steps.script.outputs.extensive_matrix }}
29+
can_skip_libm_ci: ${{ steps.script.outputs.can_skip_libm_ci }}
30+
steps:
31+
- uses: actions/checkout@v4
32+
with:
33+
fetch-depth: 100
34+
- name: Fetch pull request ref
35+
run: git fetch origin "$GITHUB_REF:$GITHUB_REF"
36+
if: github.event_name == 'pull_request'
37+
- run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT"
38+
id: script
39+
1940
test:
2041
name: Build and test
2142
timeout-minutes: 60
@@ -78,9 +99,11 @@ jobs:
7899
os: windows-2025
79100
channel: nightly-x86_64-gnu
80101
runs-on: ${{ matrix.os }}
102+
needs: [calculate_vars]
81103
env:
82104
BUILD_ONLY: ${{ matrix.build_only }}
83105
TEST_VERBATIM: ${{ matrix.test_verbatim }}
106+
CAN_SKIP_LIBM_CI: ${{ needs.calculate_vars.outputs.can_skip_libm_ci }}
84107
steps:
85108
- name: Print runner information
86109
run: uname -a
@@ -267,41 +290,21 @@ jobs:
267290
run: rustup set profile minimal && rustup default stable && rustup component add rustfmt
268291
- run: cargo fmt -- --check
269292

270-
# Determine which extensive tests should be run based on changed files.
271-
calculate_extensive_matrix:
272-
name: Calculate job matrix
273-
runs-on: ubuntu-24.04
274-
timeout-minutes: 10
275-
env:
276-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
277-
PR_NUMBER: ${{ github.event.pull_request.number }}
278-
outputs:
279-
matrix: ${{ steps.script.outputs.matrix }}
280-
steps:
281-
- uses: actions/checkout@v4
282-
with:
283-
fetch-depth: 100
284-
- name: Fetch pull request ref
285-
run: git fetch origin "$GITHUB_REF:$GITHUB_REF"
286-
if: github.event_name == 'pull_request'
287-
- run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT"
288-
id: script
289-
290293
extensive:
291294
name: Extensive tests for ${{ matrix.ty }}
292295
needs:
293296
# Wait on `clippy` so we have some confidence that the crate will build
294297
- clippy
295-
- calculate_extensive_matrix
298+
- calculate_vars
296299
runs-on: ubuntu-24.04
297300
timeout-minutes: 240 # 4 hours
298301
strategy:
299302
matrix:
300-
# Use the output from `calculate_extensive_matrix` to calculate the matrix
303+
# Use the output from `calculate_vars` to create the matrix
301304
# FIXME: it would be better to run all jobs (i.e. all types) but mark those that
302305
# didn't change as skipped, rather than completely excluding the job. However,
303306
# this is not currently possible https://github.com/actions/runner/issues/1985.
304-
include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }}
307+
include: ${{ fromJSON(needs.calculate_vars.outputs.extensive_matrix).extensive_matrix }}
305308
env:
306309
TO_TEST: ${{ matrix.to_test }}
307310
steps:

ci/ci-util.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
import json
99
import os
10+
import re
1011
import subprocess as sp
1112
import sys
12-
from dataclasses import dataclass
1313
from glob import glob, iglob
1414
from inspect import cleandoc
1515
from os import getenv
@@ -68,6 +68,10 @@
6868
"libm/src/math/arch/intrinsics.rs",
6969
]
7070

71+
# libm PR CI takes a long time and doesn't need to run unless relevant files have been
72+
# changed. Anything matching this regex pattern will trigger a run.
73+
TRIGGER_LIBM_PR_CI = ".*(libm|musl).*"
74+
7175
TYPES = ["f16", "f32", "f64", "f128"]
7276

7377

@@ -76,7 +80,6 @@ def eprint(*args, **kwargs):
7680
print(*args, file=sys.stderr, **kwargs)
7781

7882

79-
@dataclass
8083
class PrInfo:
8184
"""GitHub response for PR query"""
8285

@@ -116,7 +119,6 @@ class FunctionDef(TypedDict):
116119
type: str
117120

118121

119-
@dataclass
120122
class Context:
121123
gh_ref: str | None
122124
changed: list[Path]
@@ -142,7 +144,7 @@ def _init_change_list(self):
142144
# the PR number), and sets this as `GITHUB_REF`.
143145
ref = self.gh_ref
144146
eprint(f"using ref `{ref}`")
145-
if ref is None or "merge" not in ref:
147+
if not self.is_pr():
146148
# If the ref is not for `merge` then we are not in PR CI
147149
eprint("No diff available for ref")
148150
return
@@ -170,6 +172,10 @@ def _init_change_list(self):
170172
)
171173
self.changed = [Path(p) for p in textlist.splitlines()]
172174

175+
def is_pr(self) -> bool:
176+
"""Check if we are looking at a PR rather than a merge."""
177+
return self.gh_ref is not None and "merge" in self.gh_ref
178+
173179
@staticmethod
174180
def _ignore_file(fname: str) -> bool:
175181
return any(fname.startswith(pfx) for pfx in IGNORE_FILES)
@@ -196,6 +202,15 @@ def changed_routines(self) -> dict[str, list[str]]:
196202

197203
return ret
198204

205+
def can_skip_libm_ci(self) -> bool:
206+
"""If this is a PR and no libm files were changed, allow skipping libm
207+
jobs."""
208+
209+
if self.is_pr():
210+
return all(not re.match(TRIGGER_LIBM_PR_CI, str(f)) for f in self.changed)
211+
212+
return False
213+
199214
def make_workflow_output(self) -> str:
200215
"""Create a JSON object a list items for each type's changed files, if any
201216
did change, and the routines that were affected by the change.
@@ -216,9 +231,10 @@ def make_workflow_output(self) -> str:
216231
eprint("Skipping all extensive tests")
217232

218233
changed = self.changed_routines()
219-
ret = []
234+
extensive_matrix = []
220235
total_to_test = 0
221236

237+
# Figure out which extensive tests need to run
222238
for ty in TYPES:
223239
ty_changed = changed.get(ty, [])
224240
ty_to_test = [] if skip_tests else ty_changed
@@ -230,8 +246,13 @@ def make_workflow_output(self) -> str:
230246
"to_test": ",".join(ty_to_test),
231247
}
232248

233-
ret.append(item)
234-
output = json.dumps({"matrix": ret}, separators=(",", ":"))
249+
extensive_matrix.append(item)
250+
251+
ret = {
252+
"extensive_matrix": extensive_matrix,
253+
"can_skip_libm_ci": str(self.can_skip_libm_ci()).lower(),
254+
}
255+
output = json.dumps(ret, separators=(",", ":"))
235256
eprint(f"output: {output}")
236257
eprint(f"total extensive tests: {total_to_test}")
237258

ci/run.sh

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,14 @@ done
174174

175175
# Test libm
176176

177+
# Make sure a simple build works
178+
cargo check -p libm --no-default-features --target "$target"
179+
180+
if [ "$CAN_SKIP_LIBM_CI" = "true" ]; then
181+
echo "skipping libm PR CI"
182+
exit
183+
fi
184+
177185
mflags=()
178186

179187
# We enumerate features manually.
@@ -226,10 +234,6 @@ case "$target" in
226234
*windows-gnu) mflags+=(--exclude libm-macros) ;;
227235
esac
228236

229-
# Make sure a simple build works
230-
cargo check -p libm --no-default-features --target "$target"
231-
232-
233237
if [ "${BUILD_ONLY:-}" = "1" ]; then
234238
# If we are on targets that can't run tests, verify that we can build.
235239
cmd=(cargo build --target "$target" --package libm)

0 commit comments

Comments
 (0)