summaryrefslogtreecommitdiff
path: root/.github/workflows/build.yml
diff options
context:
space:
mode:
authorHa Thach <[email protected]>2026-08-25 09:46:42 +0700
committerGitHub <[email protected]>2026-08-25 09:46:42 +0700
commitda255b1d2db10b8f31332a779b2a526f579acee1 (patch)
tree154c8b8b9cf48f4a111edd385b8df7cc6919f3b8 /.github/workflows/build.yml
parentaa0f4a40b59012e6ab421949c153088ca4984df4 (diff)
ci: an empty selection must build nothing, plus selector follow-ups (#3845)
ci: an empty selection must build nothing, plus selector follow-ups A PR whose build axis legitimately selected nothing rebuilt everything. build.yml reads .build.families twice - as a |-joined regex, and implicitly as "is anything selected" - but tested only -z "$FAMILY_REGEX", which an empty list and a charset-rejected one both satisfy while meaning opposite things. ci_set_matrix had already returned the correct all-empty matrix; the fall-open branch discarded it. #3842 and #3840 each spent 74 cmake legs on it. Branch on the two cases instead, rename FAM_* to FAMILY_*, and cover the block with a test that extracts it from build.yml and executes it - it had no test at all, which is how this shipped through two merges. Follow-ups to the same machinery: glob.escape the repo root at five sites, so a checkout path containing [ or * stops failing closed; drop the ci-full label, read after the matrix was already computed and so never functional; delete 13 mcu:MKL25ZXX / mcu:SAME5X skip tokens matching no board; carry the rule table in the module docstring, guarded against drift; and pin six selection behaviours a mutation pass proved untested. Cut the selector's cost 1.8x (26.0s -> 14.6s) with 0 divergences over 260 paths, and stop scoping the membrowse upload by the PR example filter.
Diffstat (limited to '.github/workflows/build.yml')
-rw-r--r--.github/workflows/build.yml35
1 files changed, 22 insertions, 13 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 39a4e7afd..c26fe5cf8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -68,14 +68,9 @@ jobs:
with:
fetch-depth: 0
- # The `ci-full` PR label turns the scoping off for one PR: no selection file is
- # written, so both matrices and every rig job fall back to the unscoped behaviour.
- # An escape hatch is the point - a selector bug under-selects SILENTLY, and without
- # a label the only routes back to a full matrix are accidental (touch an
- # unclassified path, or break the selector badly enough that it falls open).
- name: CI selection (PR only)
id: hil-select
- if: github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'ci-full')
+ if: github.event_name == 'pull_request'
env:
BASE_REF: ${{ github.base_ref }}
run: |
@@ -179,29 +174,43 @@ jobs:
# treats false like null, so .build.full is compared explicitly.
EXAMPLE_MAP='{}'
BUILD_FILTERED='false'
- FAM_REGEX=''
+ FAMILY_REGEX=''
if [ -n "$BUILD_SELECT_FILE" ]; then
EXAMPLE_MAP=$(jq -c '.build.family_examples // {}' "$BUILD_SELECT_FILE") || EXAMPLE_MAP='{}'
BUILD_FILTERED=$(jq -r 'if (.build? | type) == "object" and .build.full == false then "true" else "false" end' "$BUILD_SELECT_FILE") || BUILD_FILTERED='false'
if [ "$BUILD_FILTERED" = "true" ]; then
- FAM_REGEX=$(jq -r '.build.families | join("|")' "$BUILD_SELECT_FILE") || FAM_REGEX=''
+ FAMILY_COUNT=$(jq -r '.build.families | length' "$BUILD_SELECT_FILE") || FAMILY_COUNT=0
+ FAMILY_REGEX=$(jq -r '.build.families | join("|")' "$BUILD_SELECT_FILE") || FAMILY_REGEX=''
# family names come from hw/bsp dir names, which rule 6 reads straight out
# of the PR's diff path - and this is interpolated raw into a
# `name_is_regexp` artifact pattern, so a regex metacharacter there would
# silently match another family's baseline
- case "$FAM_REGEX" in
+ FAMILY_REJECTED=0
+ case "$FAMILY_REGEX" in
*[!-A-Za-z0-9_\|]*)
echo "::warning::unexpected characters in the family list - dropping the scoping"
- FAM_REGEX='' ;;
+ FAMILY_REGEX=''; FAMILY_REJECTED=1 ;;
esac
- if [ -z "$FAM_REGEX" ]; then
- # all three drop together, as CircleCI's fall-open does. Resetting only
+ # An EMPTY families list and a REJECTED one both leave FAMILY_REGEX empty and
+ # mean opposite things, so branch on which happened. Testing `-z` alone sent
+ # every nothing-selected PR down the fall-open path: a docs/.gitignore diff
+ # (#3842) and a test/hil-only diff (#3840) each rebuilt all 74 cmake legs
+ # after the selector had correctly chosen none.
+ if [ "$FAMILY_REJECTED" = "1" ]; then
+ # unusable: fall open, and all three drop together. Resetting only
# build_filtered leaves the build scoped while code-metrics takes the
# UNSCOPED branch, diffing a 1-family run against the full averaged
# baseline and publishing that as the PR's code-size impact.
BUILD_FILTERED='false'
EXAMPLE_MAP='{}'
MATRIX_JSON=$(python .github/scripts/ci_set_matrix.py)
+ elif [ "$FAMILY_COUNT" = "0" ]; then
+ # legitimate nothing-selected. MATRIX_JSON already holds the all-empty
+ # matrix ci_set_matrix produced from this selection - keep it, so every
+ # leg skips. Nothing is built, so there is nothing to compare a baseline
+ # against: build_filtered goes false to keep code-metrics off the scoped
+ # path, and EXAMPLE_MAP stays '{}' (family_examples is empty anyway).
+ BUILD_FILTERED='false'
fi
fi
fi
@@ -210,7 +219,7 @@ jobs:
echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT
echo "example_map=$EXAMPLE_MAP" >> $GITHUB_OUTPUT
echo "build_filtered=$BUILD_FILTERED" >> $GITHUB_OUTPUT
- echo "build_families_regex=$FAM_REGEX" >> $GITHUB_OUTPUT
+ echo "build_families_regex=$FAMILY_REGEX" >> $GITHUB_OUTPUT
# HIL matrix (merged from tinyusb + hifiphile configs), scoped on PRs.
# Scoping is best-effort too: fall back to the unscoped (full) matrix.