Commit graph zephyr/scripts
Author SHA1 Message Date
Anas Nashif
f20c8f37d1 twister: add post-build checks, detect cloned git repos
Add a new "post_build" operation to the twister build pipeline that runs
checks against the freshly built artifacts before metrics gathering. The
build stage hands off to post_build, which fails the instance (ERROR,
missing cases BLOCKed) if any check reports a problem.

The first check, check_no_nested_git_repos, walks the build directory for
any nested git repository (a .git directory or file) and fails the build
if found. A test or platform should never clone a git tree into its build
directory; enforcing this per-build attributes the failure to the specific
test instance and works for local runs as well as CI.

The checks are gated behind a new --post-build-checks option and are
disabled by default, as they add a build-directory walk per build. The
option is enabled in the twister CI workflow (TWISTER_COMMON), which also
drops the previous CI-only "find .git" step.

Added unit tests for the new operation, the check, and the option gating,
and updated the existing build-op process cases for the new transition.
Ran: ZEPHYR_BASE=$PWD python -m pytest
scripts/tests/twister/test_runner.py (144 passed).

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-19 22:38:09 +02:00
David Brown
0b3b73e034 ci: compliance: exclude split vulnerability files from Kconfig check
The KconfigBasic check skips doc/security/vulnerabilities.rst because
old CVE entries often reference Kconfig symbols that have since been
removed. Splitting that page into per-year files under
doc/security/vulnerabilities/ moved most of those entries out from
under the existing exclusion, so extend the pathspec to cover the
whole directory.

Signed-off-by: David Brown <david.brown@linaro.org>
Assisted-By: Claude:opus-4.8
2026-06-18 14:39:22 -04:00
Chris Friedt
d77ae038cb scripts: release: list_backports: format script using ruff
Format the script using ruff to avoid future formatting issues.

Signed-off-by: Chris Friedt <chris@fr4.co>
2026-06-18 08:57:38 -04:00
Chris Friedt
e6af1868d7 scripts: release: list_backports: use datetime.UTC
Fix pylint errors for compliance.

```
Python lint error (UP017) see \
https://docs.astral.sh/ruff/rules/datetime-timezone-utc: \
Use `datetime.UTC` alias
```

Remove the unused import `datteime.timezone` as per

```
Python lint error (F401) see \
  https://docs.astral.sh/ruff/rules/unused-import: \
  `datetime.timezone` imported but unused
```

Signed-off-by: Chris Friedt <chris@fr4.co>
2026-06-18 08:57:38 -04:00
Chris Friedt
30a2d75312 scripts: release: list_backports: update deprecated auth mechanism
Previously, the script used `gh = Github(args.token)` which was deprecated
in release 1.59 of PyGithub. The warning was later upgraded to an
exception as of PyGithub 2.0.

```shell
list_backports.py:316: DeprecationWarning: Argument login_or_token is \
deprecated, please use auth=github.Auth.Token(...) instead
  gh = Github(args.token)
Traceback (most recent call last):
...
```

Fixes #111374

Signed-off-by: Chris Friedt <chris@fr4.co>
2026-06-18 08:57:38 -04:00
Anas Nashif
346d415a00 scripts: ci: test_plan_v2: handle missing twister output
NamedTemporaryFile(delete=False) creates the partial output file up
front, so os.path.exists() was always true and the empty/missing-output
guard never fired. When twister errored without writing results, the
code fell through to json.load() on an empty file and crashed.

Guard against a zero-byte file and catch JSONDecodeError so a failed or
truncated twister run returns an empty suite list instead of raising.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-18 05:33:00 -04:00
Sreekanth Boga
fc083043ac scripts: build: gen_relocate: parse align suffix before section flags
assign_to_correct_mem_region() reads an optional per-LOCATION MPU alignment
from a numeric suffix on the memory region name (e.g. "SRAM_4" -> 4-byte
align) via memory_region.partition('_') followed by int(align_size). A
LOCATION can also carry a "|COPY" or "|NOKEEP" flag, but that flag is only
stripped later (memory_type.split("|", 1)[0]). When both are present, e.g.
"SRAM_4|COPY", the align parse runs first and int("4|COPY") raises
ValueError, aborting the build.

Split the "|COPY"/"|NOKEEP" flag off the region name before parsing the
numeric align suffix, then re-attach it so the existing NOKEEP handling and
region naming are unchanged. Behavior is identical for every existing
LOCATION; only the previously-crashing align+flag combination is fixed.

Signed-off-by: Sreekanth Boga <sreekanth@meta.com>
2026-06-18 08:03:46 +02:00
Fin Maaß
1537081212 ci: test_plan: fix _macro_to_compat
fix _macro_to_compat for compatibles, that
dont have a vendor or a separator like
"ns16550".

Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
2026-06-17 16:35:31 -04:00
Robert Lubos
731bcf72c7 lib: os: zvfs: Add additive eventfd count mechanism
Similarly to the existing CONFIG_ZVFS_OPEN_ADD_SIZE_* mechanism used to
size the file descriptor table, allow subsystems to declare their eventfd
count requirements via CONFIG_ZVFS_EVENTFD_ADD_SIZE_* Kconfig options.
These are summed up at build time and compared against
CONFIG_ZVFS_EVENTFD_MAX, with the larger of the two values used to size
the eventfd table, exposed as the ZVFS_EVENTFD_SIZE compile definition.

A new CONFIG_ZVFS_EVENTFD_IGNORE_MIN option allows to override the
calculated requirement and use CONFIG_ZVFS_EVENTFD_MAX as-is.

As each eventfd also consumes a file descriptor, the resulting eventfd
count is now reserved in the file descriptor table as well, replacing the
former CONFIG_ZVFS_OPEN_ADD_SIZE_EVENTFD option which only accounted for
CONFIG_ZVFS_EVENTFD_MAX.

The WPA supplicant requirement is moved from a CONFIG_ZVFS_EVENTFD_MAX
default into a dedicated
CONFIG_ZVFS_EVENTFD_ADD_SIZE_WIFI_NM_WPA_SUPPLICANT option.

Assisted-by: Cursor:Claude Opus 4.8
Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
2026-06-17 11:59:43 -04:00
Benjamin Cabé
67c6eb750e scripts: zspdx: assign generated files to their generating build target
Generated source files that live under the build directory (e.g.
zephyr/isr_tables.c, zephyr/misc/generated/configs.c) were being listed
under the "app" build package (the one that produces libapp.a) even
though they are not sources of libapp.a.

All build-target components share the build directory as their base_dir,
so findOwningComponent() resolved ownership purely by path prefix and
returned whichever build target happened to be iterated first ("app")
for every file under the build directory. The CMake codemodel reports
these generated files with absolute build-tree paths, so the previous
path-only search could not tell the targets apart.

Carry the build target that referenced each source through the pending
queue and let findOwningComponent() prefer that target when the file
lives under the build directory. Generated files now land in the
component that actually generates them (e.g. configs.c -> zephyr,
isr_tables.c -> zephyr_final) instead of the app package.

Also normalize non-absolute source paths joined from the codemodel so a
relative build-tree path cannot lexically alias the app sources
directory.

Fixes #108005

Assisted-by: Claude:opus-4.8
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
2026-06-17 11:58:28 -04:00
Benjamin Cabé
7a7a95244a scripts: zspdx: migrate SBOM generation to format-agnostic model
Rework the SBOM build pipeline to populate the format-agnostic
zspdx.model and emit SPDX 2.x through SPDX2Serializer instead of the
legacy writer:

- Rewrite the walker to build an SBOMGraph of components, files and
  relationships.
- Refactor the scanner to scan the SBOMGraph.
- Route makeSPDX through the SPDX 2.x serializer.
- Remove the now-unused legacy datatypes and writer modules.

No user-visible change to the SPDX 2.x output beyond the new
generation path.

Assisted-by: Claude:opus-4.8
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
2026-06-17 11:58:28 -04:00
Benjamin Cabé
bb46f8daab scripts: zspdx: add SPDX 2.x serializer backend
Add a format-agnostic serializer framework (zspdx.serializers) and an
SPDX 2.x tag-value serializer
(zspdx.serializers.spdx2.SPDX2Serializer) that consumes the
zspdx.model SBOMGraph. It is not yet wired into the SBOM build path;
that switch is done in a follow-up change.

Mark the legacy zspdx.writer functions as deprecated.

Assisted-by: Claude:opus-4.8
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
2026-06-17 11:58:28 -04:00
Benjamin Cabé
3a077fca91 scripts: zspdx: introduce format-agnostic SBOM model
Add zspdx.model, a set of format-agnostic dataclasses (SBOMGraph,
SBOMDocument, SBOMComponent, SBOMFile, SBOMRelationship and the
ComponentPurpose/RelationshipType enums) meant to back both SPDX 2.x
and SPDX 3.0 serialization in later changes.

Mark the legacy SPDX 2.x structures in zspdx.datatypes as deprecated;
they are kept for backward compatibility during the migration.

Assisted-by: Claude:opus-4.8
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
2026-06-17 11:58:28 -04:00
Anas Nashif
7d823f1d3b ci: set_assignee: apply ruff format
Run file through `ruff format` to fix style issues.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-17 11:58:16 -04:00
Anas Nashif
83d1ac6781 scripts: ci: set_assignees: preserve additional_reviews in overflow path
After the previous commit (_add_reviewers: fix reviewer overflow
fallback), the overflow path uses only primary_maintainers as
candidates.  This had a side effect: users in additional_reviews
(maintainers of MAINTAINERS.yml-changed areas) were silently dropped
when the PR was already at the MAX_REVIEWERS limit, because those
users live in collab (which is discarded in overflow) but not in
primary_maintainers.

People in additional_reviews are specifically chosen because they are
responsible for changed MAINTAINERS.yml areas and must be notified of
those changes; dropping them defeats the purpose of the feature.

Fix: add an extra_reviewers parameter (frozenset) to _add_reviewers.
In the overflow path the candidate list becomes:

    primary_maintainers + sorted(extra_reviewers)

deduplicated via dict.fromkeys.  In the normal path the parameter is
unused (additional_reviews is already part of collab, which serves as
the candidate list).  The same four filters (author, existing reviewer,
self-removed, collaborator status) are applied to all candidates in
both paths.

Call-site change in process_pr: the trigger condition for the reviewer
step is relaxed from 'if collab' to 'if collab or additional_reviews'
so that a PR touching only MAINTAINERS.yml (empty collab) still
notifies the area maintainers.

Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-17 11:58:16 -04:00
Anas Nashif
8f121cf069 scripts: ci: set_assignees: fix reviewer overflow fallback
When the PR already has MAX_REVIEWERS or more reviewers the old
fallback set was list(all_maintainers.keys()) — the union of all area
maintainers across every file touched by the PR.  For a broad PR that
touches many areas this set can be large and unfiltered, so:

  1. The fallback could push the reviewer count far above the 15-user
     limit that GitHub enforces per review request.
  2. The PR author, users already on the review list, users who
     previously self-removed, and non-collaborators were never skipped
     in the overflow path, even though the normal path skips all of
     them.

Fix both problems:

  * Use only the maintainers of the primary (highest-weight) area as
    overflow candidates.  The primary area's maintainers represent the
    most relevant reviewers for a PR; pulling in maintainers from all
    areas makes the signal weaker, not stronger.

  * Apply the same four filters (author, existing reviewer, self-
    removed, collaborator status) to the overflow candidates.

Update the module docstring 'Reviewer selection' section accordingly.

Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-17 11:58:16 -04:00
Anas Nashif
e1077c1162 scripts: ci: set_assignees: apply area labels in a single API call
The previous implementation called pr.add_to_labels(label) once per
label in a loop.  Each call is a separate GitHub API request and
creates a separate timeline event on the PR, adding noise for reviewers
who watch the label history.

Replace the loop with a single pr.add_to_labels(*new_labels) call.
Also filter out labels already present on the PR so re-runs do not
create redundant timeline events or waste API quota.

Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-17 11:58:16 -04:00
Anas Nashif
e04481e3c3 scripts: ci: set_assignees: add full size label suite via --size-labels
By default the script only manages the 'size: XS' label.  Add an
opt-in --size-labels flag that activates the complete size label suite:

  size: XS  -- 1 commit, <=1 line changed, no manifest file touched
  size: S   -- <=9 lines changed
  size: M   -- <=49 lines changed
  size: L   -- <=499 lines changed
  size: XL  -- >499 lines changed

The new update_size_labels() function computes the correct bucket,
removes any stale size label already on the PR, and queues the correct
label for application.  The XS bucket reuses the existing stricter
rules (single commit, manifest-file exclusion) from
update_size_xs_label().

When --size-labels is not given, behaviour is identical to before.

New module-level constants:
  _SIZE_LABELS     -- frozenset of all label names this script manages
  _SIZE_THRESHOLDS -- (max_lines, label) table for S/M/L buckets

Update the module docstring 'Labeling strategy' section to document
the full suite and the --size-labels flag.

Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-17 11:58:16 -04:00
Anas Nashif
7bf5064d46 scripts: ci: set_assignees: skip closed/merged PRs in process_pr
Between the GitHub search query in main() and the individual process_pr
call, a PR can be closed or merged (e.g. by a concurrent merge or a
maintainer closing it during the batch run).  Without a state check,
the script would add labels and review requests to an already-closed
PR, creating spurious timeline events.

Add an early return when pr.state is not 'open'.

Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-17 11:58:16 -04:00
Anas Nashif
11ed9363bb scripts: ci: set_assignees: skip draft PRs in process_pr
When -P/--pull_request is used to target a single PR, the draft state
was never checked.  The batch search in main() already excludes drafts
via -is:draft, but process_pr itself could still be called on a draft
when invoked directly.

Draft PRs are work-in-progress; assigning reviewers and labels before
the author marks them ready creates noise and may trigger notifications
on incomplete work.

Add an early return at the top of process_pr when pr.draft is True.

Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-17 11:58:16 -04:00
Anas Nashif
77a490b395 scripts: ci: set_assignees: add detailed strategy documentation
Expand the module docstring with a thorough description of how the
script decides what to do for each PR and issue:

- Labeling strategy: area label union, MAX_LABELS cap, size: XS rules.
- Area weighting: CMakeLists.txt and meta-area scoring exceptions,
  Platform (is_instance) double-count prevention.
- Reviewer selection: candidate ordering, filtering rules (author,
  existing reviewers, non-collaborators, self-removed users), the
  MAX_REVIEWERS fallback strategy, and the vacancy cap.
- Assignee selection: meta-only shortcut, weight-0/no-maintainer skip,
  author exclusion, non-platform vs. platform priority, last-resort
  highest-file-count fallback.
- Manifest / MAINTAINERS.yml change handling for west.yml,
  submanifests/optional.yaml, and MAINTAINERS.yml diffs.
- Issue assignment label-matching logic.
- Module PR assignment across active west projects.

Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-17 11:58:16 -04:00
Anas Nashif
1f7db2e33a scripts: tests: ci: add pytest suite for set_assignees
Add scripts/tests/ci/test_set_assignees.py with 50 tests covering the
pure-logic and lightly-stateful helpers in set_assignees.py.

Heavy third-party dependencies (PyGithub, west, get_maintainer) are
stubbed out in sys.modules before the SUT is imported so the suite
runs without a GitHub token or a full Zephyr build environment.

Coverage:

  load_areas         - includes/excludes areas based on
  		       files/files-regex keys
  set_or_empty       - missing key, None value, empty list
  _diff_area_entry   - maintainer/collaborator/label/files/status changes
  compare_areas      - added, removed, changed, unchanged areas
  update_size_xs_label
                     - XS qualification criteria (commits, additions,
                       deletions, manifest files)
                     - stale label removal with and without dry-run
  _pick_assignees    - non-platform priority, platform fallback, author
                       exclusion, meta-only area, zero-count skip,
                       empty-maintainer skip, all-maintainers fallback,
                       zero num_files divide-by-zero guard
  setup_logging      - verbose=0/1/2/3 log level mapping

Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-17 11:58:16 -04:00
Anas Nashif
3311886c77 scripts: ci: set_assignees: extract size XS label logic into helper
Move the 'size: XS' label add/remove logic out of process_pr() and
into a dedicated update_size_xs_label() function.  The set of manifest
files that disqualify a PR from the label is promoted to a module-level
constant (_MANIFEST_FILES) so it is defined in one place.

No behavioural change.

Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-17 11:58:16 -04:00
Anas Nashif
b09de8e4ab scripts: ci: set_assignees: overhaul for readability and correctness
Replace ad-hoc log()/print() mix with Python's logging module.
Verbosity levels are now -v (INFO) and -vv (DEBUG).

Fix a bug in reviewer enumeration: get_review_requests() returns a
(users, teams) tuple; the old enumerate() loop was treating the
list index as a page number and querying teams instead of users,
causing existing reviewers to be missed and potentially re-added.

Fix silent error swallowing in _assign_maintainers: the original
try/except wrapped the entire loop, aborting all remaining assignees
on the first unknown-user exception. Each user lookup is now
handled independently.

Fix labels.add('size: XS') replacing the already-collected label
set with a one-element set literal.

Remove an O(n^2) get_collaborators_for_path() inner loop that ran
once per (file x area) pair; moved outside both loops.

Remove dead repo_fullname and token parameters from compare_areas().
Remove redundant if len(area.maintainers) > 0 guard that was
unreachable due to the continue statement directly above it.

Extract _pick_assignees(), _add_reviewers(), _assign_maintainers()
and _diff_area_entry() helpers to break up the 200-line process_pr().

Replace multi-pass filter(lambda ...) chains in process_manifest()
with readable set comprehensions.

Add module docstring so argparse --help displays a description.

Replace all inline magic numbers with named module-level constants:
MAX_FILES, MAX_REVIEWERS, MAX_LABELS, API_SLEEP_SECONDS, META_AREAS.

Fix misleading log message in MAINTAINERS.yml processing branch that
said "skipping" immediately before processing the changes.

Fix typo "adding reviewrs".

Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-17 11:58:16 -04:00
Shan Pen
39939588ed scripts: west: fix zsh board and snippet completion
Pass board targets and snippet names to _describe through local arrays.
This avoids treating the first completion candidate as an array name.

Assisted-by: Codex:GPT-5
Signed-off-by: Shan Pen <bricle031@gmail.com>
2026-06-17 08:04:27 +02:00
Sreekanth Boga
ea69e6faba linker: cbprintf: recognize relocated rodata for dictionary string logging
cbprintf dictionary logging ships read-only string arguments to the host
as bare pointers (resolved by address) and deep-copies the rest,
choosing via linker_is_in_rodata() -- which only checks the default
__rodata_region. Strings in libraries moved by
zephyr_code_relocate(... CCM_RODATA/SMEM_RODATA) land in
.ccm_rodata_reloc / .smem_rodata_reloc, outside that range, so they are
misclassified as transient and the dictionary backend cannot
reconstruct them: string columns render blank/garbled.

Both halves are required -- a firmware-only fix ships pointers the host
cannot resolve, and a database-only fix still ships them as transient:

- linker/utils.h: linker_is_in_rodata() also accepts the relocated
  spans __ccm_rodata_reloc_* / __smem_rodata_reloc_*. These are declared
  as weak symbols and NULL-guarded so builds that do not relocate rodata
  are unaffected.
- database_gen.py: include relocated rodata sections in the dictionary
  string extraction so the host can resolve those pointers.

Signed-off-by: Sreekanth Boga <sreekanth@meta.com>
2026-06-17 08:03:00 +02:00
Josuah Demangeon
7a263c0723 west: runners: openocd: log to stderr by default
Never hide OpenOCD errors, always log them out to stderr, except when
the user specifies --log-file. Useful for when GDB or other tool uses
a TUI which makes the output garbled from mixing OpenOCD output with GDB.

Signed-off-by: Josuah Demangeon <me@josuah.net>
2026-06-16 12:59:00 -05:00
Luca Burelli
17100cda9a scripts: gen_relocate_app: fix LLEXT heap sections
Since 8bcc333e65 ("llext: custom sections for
heap"), heaps used by LLEXT are placed in dedicated sections that are not
named with a ".noinit." prefix. This causes the gen_relocate_app.py script
to fail to recognize these as usable for relocation, so the CMake function
zephyr_code_relocate() cannot be used on those.

This change adds the LLEXT heap sections to the list of sections that are
categorized as NOINIT, ensuring they are available for the relocation
process.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2026-06-16 17:47:31 +02:00
Eryk Szpotanski
47850d70be scripts: instrumentation: zaru: use full thread ID
Removes the truncation of thread ID, as it prevents other scripts/apps
from e.g. matching thread ID and thread name.

Signed-off-by: Eryk Szpotanski <eszpotanski@antmicro.com>
2026-06-16 17:46:52 +02:00
Daniele Cloralio
9e20df63e0 scripts: build: skip non-device _device_ symbols in elf_parser
Fix a crash in device dependency generation when CONFIG_DEVICE_DEPS is
enabled and the ELF contains helper objects whose names start with
__device__ prefix but are not actual struct device instances.

Filter __device__ symbols by address range: real struct devices are
allocated consecutively inside the device section [_device_list_start,
_device_list_end].

Signed-off-by: Daniele Cloralio <d.cloralio@arduino.cc>
2026-06-16 17:46:38 +02:00
Grzegorz Chwierut
a6b3950ede twister: Allow --shuffle-tests without --subset
Previously --shuffle-tests required --subset to be set, which
limited shuffling to subset-based runs. Remove that restriction
so test execution order can be randomized in any run.

When shuffling with a random seed across multiple subsets, not
all tests are guaranteed to be covered. Add a warning suggesting
a fixed seed via --shuffle-tests-seed in that case.

Signed-off-by: Grzegorz Chwierut <grzegorz.chwierut@nordicsemi.no>
2026-06-16 10:29:09 +02:00
Anas Nashif
7d936323da ztest: show parameter instance and index in test output
When a ZTEST_P test is dispatched with multiple parameter values the
console output previously repeated the same test name for every
invocation, making it impossible to tell which parameter value caused
a failure at a glance.

Format a unique display name for each parameterized invocation using
the same bracket convention as Google Test:

  test_name[instance_name/N]

where N is the 0-based index, or a custom label returned by the
optional name_cb callback:

  test_name[instance_name/custom_label]

The display name is stored in a 128-byte buffer inside the existing
z_ztest_param_ctx struct and is used only by TC_START() and
Z_TC_END_RESULT() inside run_test(); the base test->name is unchanged
everywhere else (stats, verbose summary).

Non-parameterized tests are not affected: the display_name buffer is
cleared before each plain run_test() call.

The Twister Test harness test_case_start_pattern is relaxed from the
character-class [a-zA-Z0-9_-]+ to \S+ so it can parse the new
[instance/N] suffix; the end-of-test pattern already used \S* and
requires no change.

Before:
  START - test_param_index
   PASS - test_param_index in 0.000 seconds
  START - test_param_index
   PASS - test_param_index in 0.000 seconds

After:
  START - test_param_index[idx_check/0]
   PASS - test_param_index[idx_check/0] in 0.000 seconds
  START - test_param_index[idx_check/1]
   PASS - test_param_index[idx_check/1] in 0.000 seconds

Assisted-by: GitHub Copilot:claude-sonnet-4-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-15 12:17:37 -04:00
Lukasz Fundakowski
5c50f0a646 twister: reports: split Reporting class by responsibility
Extract XUnitXMLReport and JsonReport classes from the monolithic
Reporting class so that each class has a single, well-defined
responsibility. Move build error parsing methods
(_parse_cmake_build_failure, _parse_build_failure, get_detailed_reason)
to a dedicated class.

Rename xunit_report() to XUnitXMLReport.create() and
xunit_report_suites() to XUnitXMLReport.create_with_all_testsuites()
to better reflect their purpose. Add type annotations to new class
constructors and key methods.

Update Reporting.reports() to instantiate and delegate to the new
classes instead of calling methods on self directly.

Signed-off-by: Lukasz Fundakowski <lukasz.fundakowski@nordicsemi.no>
2026-06-15 12:14:51 -04:00
Marc Herbert
e47fc16936 scripts: west_commands: allow several forward_logging_to_west() handlers
`forward_logging_to_west()` just added by commit 5ac32bd7dd ("scripts:
west_commands: bridge module loggers to WestCommand output") was
silently doing nothing whenever the loggers already had one handler or
more. This was inherited from the earlier code (which had a much
narrower scope) to minimize changes in a big refactoring and migration
but I can't find a rationale. The design of
https://docs.python.org/3/howto/logging.html is very clearly meant to
support multiple handlers per logger and there is no reason to restrict
that. Considering this new `forward_logging_to_west()` approach is
likely to be used as a template for a more generic, non-Zephyr specific
implementation/recommendation in
https://github.com/zephyrproject-rtos/west/issues/952, we don't want it
to set the wrong example. So, remove that single-handler restriction and
also add some... debug logs (!) inside forward_logging_to_west().

Print an error and return when trying to add the _same_ handler
instance.

Signed-off-by: Marc Herbert <marc.herbert@gmail.com>
2026-06-15 10:21:20 +02:00
Marc Herbert
b3de789788 scripts: west_commands: forward 'runners' logger only once
No need to configure logging once per domain, that never made sense.

In 2019, commit ddce583ca2 ("scripts: west_commands: decouple runners
pkg from west") adds the `logging.getLogger('runners').addHandler(...)`
configuration code for the first time. No --sysbuild at the time.

In 2020, big refactoring commit eb95bed552 ("scripts: west_commands:
fix argument handling with runners.yaml") shuffles things around but the
`do_run_common()` function and the
`getLogger('runners').addHandler(...)`` setup call now inside it are
still called only once.

In 2022, commit 8408af6d7c ("scripts: west commands to support
--domain") starts running `do_run_common()` in loop (once for each
#domain). Instead of moving the logging configuration outside of the for
loop, it adds a check to configure only on the first domain iteration. I
can't see any rationale for not moving that logging setup out of the
domain `for` loop. Pull request #40555 was a massive new feature with 9
commits and a lot of lines changed, so I bet @tejlmand did this only
because it was quick and because he had a lot of other, bigger fish to
try.

In may 2026, commit 5ac32bd7dd ("scripts: west_commands: bridge module
loggers to WestCommand output") generalizes the forwarding approach and
includes its "only" the first time logic. In
https://github.com/zephyrproject-rtos/zephyr/pull/109165/changes#r3294817222
I wondered about this logic and I asked some vague, low priority
questions that were left unanswered.  As part of this refactoring, the
connection with --sysbuild got lost.

In https://github.com/zephyrproject-rtos/zephyr/pull/110671 where I
naively tried to "promote" this to an ERROR, @sylvioalves immediately
spotted the issue and reconnected with --sysbuild, sharing how to
reproduce a spurious ERROR.

In this commit, I'm finally moving the logging setup out of the domain
`for` loop!

Phew.

Signed-off-by: Marc Herbert <marc.herbert@gmail.com>
2026-06-15 10:21:20 +02:00
Tahsin Mutlugun
d387fde56f west: runners: openocd: Use POSIX-style paths for log files
OpenOCD cannot handle Windows-style backslash paths, so switch
to POSIX-style paths for log file handling.

Signed-off-by: Tahsin Mutlugun <Tahsin.Mutlugun@analog.com>
2026-06-12 21:46:48 +02:00
Anas Nashif
e9703ccd84 ci: scripts: add SARIF summary step
Add scripts/ci/sarif_summary.py and a new 'Summarize SARIF results'
workflow step that runs after the scan and artifact upload.

The script reads results.sarif and:

- Writes a Markdown table to $GITHUB_STEP_SUMMARY, which surfaces on
the GitHub Actions job summary page.  Rules are sorted by
classification (mandatory first, then required, then advisory) and
by descending violation count within each group.  The header shows
the total violation count and the number of distinct rules triggered.

- Emits one ::notice:: workflow annotation per triggered rule so each
rule ID, classification, description, and count appears in the
Actions log viewer.

Both outputs are derived from the SARIF tool.driver.rules metadata
(fullDescription.text and properties.tags) and the per-result ruleId
counts.  The script handles multi-run SARIF files and falls back to
stdout when $GITHUB_STEP_SUMMARY is not set, making it usable locally
for inspection.

Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-12 10:06:34 +02:00
Anas Nashif
551aea8da1 scripts: gen_isr_tables: use power-of-2 ALIGN in linker script
lld requires ALIGN() arguments to be powers of 2.  GNU ld accepts
arbitrary values as an extension, so this worked with GCC toolchains
but broke builds using ZEPHYR_TOOLCHAIN_VARIANT=zephyr/llvm:

  ld.lld: error: isr_tables_swi.ld:35: alignment must be power of 2

The shared ISR table entry size on 32-bit ARM is 20 bytes
(2 x sizeof(_isr_table_entry) + sizeof(size_t)), which is not a
power of 2.  The generator was emitting ALIGN(20) to advance the
location counter to the next entry boundary.

Since each entry section fills exactly sizeof(entry) bytes, ALIGN is
always a no-op when the sections are placed correctly.  The only
semantically meaningful value is the struct's natural C alignment,
which equals the largest power-of-2 divisor of sizeof(entry):

  _linker_align(n) = n & -n

For entry size 20 this gives 4; for 8 it gives 8.  Using this value
produces a linker script accepted by both GNU ld and lld.

Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-12 07:52:54 +02:00
Anas Nashif
d34a8c5cf8 ci: testplan: BoilerplateFilter: skip binary files
git diff on a binary file (image, compiled object, archive)
produces only a "Binary files ... differ" header line with no
+/- content lines. _all_changes_boilerplate() found nothing to
reject in that output and returned True, causing binary files
to be consumed as boilerplate and silently dropped from the
pipeline instead of reaching IgnoreStrategy or other handlers.

Fix _is_boilerplate_only() to check for the "Binary files"
marker in the diff output immediately after the first git diff
call. When found, return False so the file is not treated as
boilerplate and passes through to downstream strategies for
proper handling.

Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-11 23:31:28 +02:00
Anas Nashif
f77be08d42 ci: testplan: ManifestStrategy: add MAINTAINERS area test lookup
For each changed west project, look up the corresponding
"West project: <name>" area in MAINTAINERS.yml and emit an
additional TwisterCall using --test-pattern arguments built
from the area's tests: list.

This complements the existing --tag <name> --integration call
with explicitly catalogued tests that may not carry a tags:
field matching the project name (e.g. mbedtls crypto suites,
mcuboot bootloader tests, lvgl GUI samples).

The maintainers_file parameter is now threaded through
build_strategies() into ManifestStrategy.__init__() so that
the MAINTAINERS.yml path is available at analysis time.

When no maintainers_file is configured the new helper returns
an empty dict and behaviour is unchanged.

Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-11 23:31:28 +02:00
Anas Nashif
f81dee46d2 ci: testplan: also skip webp files
Ignore webp files as well when processing testplan for twister and more
image extensions to the ignore list.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-11 23:31:28 +02:00
Sylvio Alves
806a6ff3fa runners: add serial port auto-detection by chip
Add a generic resolve_port_by_chip() helper to the base runner so
flash backends can pick a serial port by matching the connected
chip against the build target. It probes attached devices through
a caller-supplied detect callback and prefers a given set of USB
VIDs to avoid resetting unrelated adapters.

The esp32 runner uses it when no port is given: it probes with
esptool and flashes the first device whose chip matches CONFIG_SOC.
Identification connects to each candidate, so other attached boards
may be reset during the scan; pass --esp-device to skip probing and
target a fixed port.

Signed-off-by: Sylvio Alves <sylvio.alves@espressif.com>
2026-06-10 17:34:52 -04:00
Anas Nashif
aeb75978f3 scripts: ci: test_plan: replace – with -
Replace – with -.
The character U+2013 "–" could be confused with the ASCII character
U+002d "-", which is more common in source code.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-10 17:33:27 -04:00
Anas Nashif
4e73504479 scripts: ci: add BoilerplateFilter strategy to test_plan_v2
Add a new BoilerplateFilter consuming strategy that runs after the
existing IgnoreStrategy.  The filter inspects the actual diff of each
changed file and silently consumes those whose entire change set is
non-substantive, i.e. made up exclusively of:

  - Whitespace adjustments and blank-line additions/removals
    (detected via 'git diff -w --ignore-blank-lines').
  - SPDX-License-Identifier and SPDX-FileCopyrightText header lines.
  - Copyright notice lines.
  - Lines consisting solely of comment delimiter characters
    (/* */ // # *).

A file is only consumed when every added/removed line in its diff falls
into one of those categories.  A single substantive line (changed
statement, macro, declaration) causes the file to pass through to
downstream strategies unchanged so normal test selection proceeds.

The filter is a no-op when no git commit range is available (e.g. when
--modified-files is used without --commits), because the diff cannot be
computed in that case.

Also add 14 unit tests in scripts/tests/ci/test_test_plan_v2.py covering
the helper methods and the analyze() interface, and update the developer
documentation in doc/develop/test/ci_test_plan.rst with a new
'Boilerplate filter' section and a table row for the strategy.

Assisted-by: GitHub Copilot:claude-opus-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-10 17:33:27 -04:00
Anas Nashif
16d30c48cc scripts: tests: add tests for testplan v2
Adds unit tests for the test_plan_v2.py

Assisted-by: GitHub Copilot:claude-opus-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-10 17:33:27 -04:00
Anas Nashif
2b20124485 scripts: ci: add modular test selector test plan generation script
Add scripts/ci/test_plan_v2.py, a modular CI test-selection
tool that analyses the files changed in a Pull Request and emits a
targeted twister test plan, avoiding tests unrelated to the change
while maximising coverage of what was touched.

Architecture
============
A pipeline of independent strategies each receives the full (or
remaining) list of changed files and returns a list of TwisterCall
descriptors.  An Orchestrator executes the calls, merges results,
removes duplicates and writes testplan.json.  A shared PipelineContext
carries cross-strategy state (complexity score, per-file metrics).

Strategies (execution order)
=============================
0. ComplexityStrategy – analyses patchset complexity with pydriller
   (commit-level churn, changed-method CCN, DMM unit-complexity) and
   lizard (avg CCN delta between old and new file versions).  Emits a
   composite score into PipelineContext; no twister calls generated.

1. IgnoreStrategy – reads scripts/ci/twister_ignore.txt and silently
   consumes files matching any glob pattern (docs, tooling, workflows).

2. DirectTestStrategy – for files under tests/ or samples/, walks up
   to the nearest testcase.yaml/sample.yaml root and runs that exact
   suite with --integration.

3. SnippetStrategy – for files under snippets/, reads the snippet name
   from snippet.yml, finds tests that declare it as required_snippets
   and runs those test roots.

4. BoardStrategy – for files under boards/, enumerates all board
   variants via list_boards.py (including twister.yaml consolidated
   boards) and runs tests/integration/kernel on each variant.

5. SoCStrategy – for files under soc/, resolves SoC names from
   soc.yml, finds boards referencing those SoCs and runs
   tests/integration/kernel on them.

6. ManifestStrategy – for changed west.yml / submanifests files, diffs
   old vs new revision via git show, identifies added/removed/updated
   projects and runs --tag <module> --integration.

7. DriverCompatStrategy – for driver source files, extracts
   DT_DRV_COMPAT, finds test overlays that instantiate the compatible
   and adds those test directories as -T roots.

8. DtsBindingStrategy – for changed dts/bindings YAML files, reads the
   compatible: field and feeds it through the same compat-resolution
   chain as DriverCompatStrategy.

9. KconfigImpactStrategy – for changed Kconfig files and defconfigs,
   extracts symbol names and greps tests for .conf/.yaml files that
   enable those symbols.

10. HeaderImpactStrategy – for changed public headers, greps for
    #include users and maps them back to MAINTAINERS areas with tests.

11. MaintainerAreaStrategy – catch-all: matches remaining files against
    MAINTAINERS.yml areas and uses their tests: list.

RiskClassifierStrategy is implemented but disabled pending further
tuning of its classification rules.  When enabled it reads the
complexity score from PipelineContext to escalate NORMAL-risk files to
WIDE coverage when the score exceeds the threshold.

Output
======
* testplan.json – loaded by twister via --load-tests
* .testplan     – env-var file (TWISTER_TESTS, TWISTER_NODES,
                  TWISTER_FULL) consumed by CI orchestration

Assisted-by: GitHub Copilot:claude-opus-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-10 17:33:27 -04:00
Anas Nashif
01f0cea45d ci: gen_catalogs: enrich DTS schema and consolidate EDT gathering
Extend the DTS catalog schema produced by scripts/ci/gen_catalogs.py
with the additional fields required to eliminate duplicated logic in the
doc build:

- Each dts_sources entry now carries an "okay" boolean so consumers
  can distinguish enabled from disabled nodes without re-processing EDT
  objects.
- Each compatible entry now carries "binding_path" (workspace-relative)
  and "custom_binding" (bool) so consumers do not need access to the
  raw binding files at catalog-consumption time.
- Each board entry now carries a "runners" dict (runners list plus
  flash_runner / debug_runner) populated by the new
  gather_board_runners() helper.

build_catalog() gains an optional board_runners argument; main() now
calls gather_board_runners() and passes the result when building the
DTS catalog.

doc/_scripts/gen_boards_catalog.py is updated to import gen_catalogs
and delegate the twister/EDT gathering to it rather than duplicating
the implementation.  The public API (get_catalog, gather_board_build_info,
run_twister_cmake_only) and all surrounding logic are unchanged.

Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-10 14:53:04 -04:00
Anas Nashif
728e8d35f0 ci: add workflow that creates a dts catalog on push
Create a DTS catalog that can be used for documentation, tesplan
generation and other tooling.

This is mostly based on what already being used when building
documentation and the board catalog in the docs.

Assisted-by: GitHub Copilot:Claude Sonnet 4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-10 14:53:04 -04:00
Benjamin Cabé
dbabc3eb94 doc: guidelines: improve guidelines re picture formats/sizes
Make the documentation guidelines and board template prescriptive about
board photos: they must be WebP, capped at 600 px on their largest
dimension, and preferably use a transparent background. Add conversion
tips using cwebp and ImageMagick.

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
2026-06-10 07:47:52 +02:00
Anas Nashif
cdf11cdcb1 release: list_backports: add --check mode for PR issue enforcement
Add a --check flag intended for use in the GitHub Actions workflow.
When --check is passed with a single -p PR number, the script verifies
that the PR body contains a 'Fixes #N' (or equivalent URL) reference.
If no issue is found, a comment is posted on the PR asking the
contributor to add one, and the script exits with a non-zero status,
failing the CI check.

Assisted-by: GitHub Copilot:Claude Sonnet 4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-06-10 07:47:42 +02:00