diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 91eb2690e..59cc44c8c 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -55,6 +55,9 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v7 + with: + # Needed to diff against the base branch for newly added variants. + fetch-depth: 0 - uses: actions/setup-python@v6 with: python-version: 3.x @@ -62,11 +65,33 @@ jobs: - run: pip install -U platformio - name: Generate matrix id: jsonStep + env: + BASE_REF: ${{ github.base_ref }} + MERGE_GROUP_BASE_SHA: ${{ github.event.merge_group.base_sha }} run: | + # A new board is 'release' and gets no CI until after merge, so force-build the + # first env of each ADDED variant config. A new env in an existing one does not count. + DIFF_BASE="" + if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then + git fetch --no-tags --depth=1 origin "$BASE_REF" + DIFF_BASE=$(git merge-base FETCH_HEAD HEAD) + elif [[ "$GITHUB_EVENT_NAME" == "merge_group" ]]; then + DIFF_BASE="$MERGE_GROUP_BASE_SHA" + fi + ADDED_ARGS=() + if [[ -n "$DIFF_BASE" ]]; then + # Assign rather than pipe: a failing diff must abort the step under 'set -e', + # not silently yield an empty list and drop the new board from the matrix. + ADDED_CONFIGS=$(git diff --name-only --diff-filter=A \ + "$DIFF_BASE" HEAD -- 'variants/**/platformio.ini') + while IFS= read -r cfg; do + [[ -n "$cfg" ]] && ADDED_ARGS+=(--added-config "$cfg") + done <<<"$ADDED_CONFIGS" + fi # PRs and (for now) merge_group builds use the narrowed --level pr board # subset. Full-matrix builds run on push / schedule / workflow_dispatch. if [[ "$GITHUB_EVENT_NAME" == "pull_request" || "$GITHUB_EVENT_NAME" == "merge_group" ]]; then - TARGETS=$(./bin/generate_ci_matrix.py all --level pr) + TARGETS=$(./bin/generate_ci_matrix.py all --level pr "${ADDED_ARGS[@]}") else TARGETS=$(./bin/generate_ci_matrix.py all) fi diff --git a/bin/generate_ci_matrix.py b/bin/generate_ci_matrix.py index c3235c279..02155b59a 100755 --- a/bin/generate_ci_matrix.py +++ b/bin/generate_ci_matrix.py @@ -23,10 +23,29 @@ parser.add_argument( default=[], help="Board level to build for (omit for the 'pr' + 'release' matrix)", ) +parser.add_argument( + "--added-config", + action="append", + default=[], + metavar="PATH", + help="platformio.ini added by this PR; its first env is built regardless of board_level", +) args = parser.parse_args() outlist = [] +# A brand-new board is normally 'release', so it would get no CI until after merge. +# Build the first env of each newly added config so it is compiled at least once. +forced_envs = set() +for added_path in args.added_config: + try: + with open(added_path, encoding="utf-8") as added_file: + first_env = re.search(r"^[ \t]*\[env:([^\]]+)\]", added_file.read(), re.MULTILINE) + except OSError: + continue + if first_env: + forced_envs.add(first_env.group(1).strip()) + cfg = ProjectConfig.get_instance() pio_envs = cfg.envs() @@ -69,6 +88,9 @@ for env in all_envs: # Always include board_level = 'pr' if env["board_level"] == "pr": outlist.append(env["ci"]) + # Include the first env of a platformio.ini added by this PR + elif env["ci"]["board"] in forced_envs: + outlist.append(env["ci"]) # Include board_level = 'extra' when requested elif "extra" in args.level and env["board_level"] == "extra": outlist.append(env["ci"])