summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorCYFS <[email protected]>2026-06-26 11:05:32 +0800
committerRbb666 <[email protected]>2026-06-26 16:40:09 +0800
commit64651f968a2eafc9c92bfb5c567cfa21f5ddca4f (patch)
tree279c84bd92671d5ec9605290b61e77367f7a4180 /tools
parentc374e529c4e04b31cb4505f57f7abd217e6b62ae (diff)
ci: optimize membrowse target filtering
Diffstat (limited to 'tools')
-rw-r--r--tools/ci/membrowse_filter_targets.py116
1 files changed, 116 insertions, 0 deletions
diff --git a/tools/ci/membrowse_filter_targets.py b/tools/ci/membrowse_filter_targets.py
new file mode 100644
index 0000000000..626adade8e
--- /dev/null
+++ b/tools/ci/membrowse_filter_targets.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2026, RT-Thread Development Team
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+import argparse
+import json
+import os
+
+
+GLOBAL_FILES = {
+ ".github/membrowse-targets.json",
+ ".github/workflows/membrowse-report.yml",
+ "Kconfig",
+}
+
+GLOBAL_PREFIXES = (
+ "components/",
+ "include/",
+ "libcpu/",
+ "src/",
+ "tools/",
+)
+
+def normalize_path(path):
+ return path.replace("\\", "/").strip().lstrip("./")
+
+
+def is_ignored_change(path):
+ name = path.rsplit("/", 1)[-1]
+ return name.lower().startswith("readme") or (path.startswith("bsp/") and "/docs/" in path)
+
+
+def is_under(path, prefix):
+ path = normalize_path(path)
+ prefix = normalize_path(prefix).rstrip("/")
+ return path == prefix or path.startswith(prefix + "/")
+
+
+def read_changed_files(path):
+ with open(path, "r", encoding="utf-8") as file:
+ return [
+ changed_file
+ for changed_file in (normalize_path(line) for line in file if line.strip())
+ if not is_ignored_change(changed_file)
+ ]
+
+
+def is_global_change(path):
+ return path in GLOBAL_FILES or any(path.startswith(prefix) for prefix in GLOBAL_PREFIXES)
+
+
+def target_related_prefixes(target):
+ return [
+ normalize_path(prefix)
+ for prefix in target.get("watch_paths", [target["bsp_path"]])
+ ]
+
+
+def select_targets(targets, changed_files):
+ if not changed_files:
+ return []
+
+ if any(is_global_change(path) for path in changed_files):
+ return targets
+
+ selected = []
+ for target in targets:
+ related_prefixes = target_related_prefixes(target)
+ if any(
+ is_under(changed_file, related_prefix)
+ for changed_file in changed_files
+ for related_prefix in related_prefixes
+ ):
+ selected.append(target)
+
+ return selected
+
+
+def write_github_output(matrix, output_path):
+ if not output_path:
+ return
+
+ with open(output_path, "a", encoding="utf-8") as output:
+ output.write("matrix={}\n".format(json.dumps(matrix, separators=(",", ":"))))
+ output.write("target_count={}\n".format(len(matrix)))
+
+
+def main():
+ parser = argparse.ArgumentParser(description="Filter MemBrowse targets by changed files.")
+ parser.add_argument("--targets", required=True, help="Path to membrowse-targets.json.")
+ parser.add_argument("--changed-files", required=True, help="Path to a newline-delimited changed file list.")
+ args = parser.parse_args()
+
+ with open(args.targets, "r", encoding="utf-8") as file:
+ targets = json.load(file)
+
+ changed_files = read_changed_files(args.changed_files)
+ selected_targets = select_targets(targets, changed_files)
+
+ print("Changed files:")
+ for changed_file in changed_files:
+ print(" {}".format(changed_file))
+
+ print("Selected MemBrowse targets:")
+ for target in selected_targets:
+ print(" {}".format(target["target_name"]))
+
+ print("Selected {}/{} MemBrowse targets".format(len(selected_targets), len(targets)))
+ write_github_output(selected_targets, os.getenv("GITHUB_OUTPUT"))
+
+
+if __name__ == "__main__":
+ main()