diff --git a/.github/scripts/commit_prefix_check.py b/.github/scripts/commit_prefix_check.py index b8c14c2e3c5..a345a60eced 100644 --- a/.github/scripts/commit_prefix_check.py +++ b/.github/scripts/commit_prefix_check.py @@ -62,18 +62,28 @@ def infer_prefix_from_paths(paths): component_prefixes.add(f"{parts[1]}:") # ----- src/ → flb_xxx.* → xxx: OR src// → : ----- - # ----- src/fluent-bit.c → bin: ----- + # ----- src/ handling ----- if p.startswith("src/"): + parts = p.split("/") filename = os.path.basename(p) - if filename.startswith("flb_"): + + # src/fluent-bit.c → bin: + if filename == "fluent-bit.c": + component_prefixes.add("bin:") + continue + + # src/flb_xxx.c → xxx: + if len(parts) == 2 and filename.startswith("flb_"): core = filename[4:].split(".")[0] component_prefixes.add(f"{core}:") - elif filename == "fluent-bit.c": - component_prefixes.add("bin:") - else: - parts = p.split("/") - if len(parts) > 1: - component_prefixes.add(f"{parts[1]}:") + continue + + # src//... → : + if len(parts) > 2: + src_dir = parts[1] + component_prefixes.add(f"{src_dir}:") + continue + # prefixes = component prefixes + build: if needed prefixes |= component_prefixes @@ -170,6 +180,23 @@ def validate_commit(commit): expected_lower = {p.lower() for p in expected} subj_lower = subject_prefix.lower() + + # ------------------------------------------------ + # config_format conditional umbrella rule + # ------------------------------------------------ + if "config_format:" in expected_lower: + non_build = { + p for p in expected_lower + if p not in ("build:", "cmakelists.txt:") + } + + # Allow ONLY if all non-build prefixes are config_format: + if non_build != {"config_format:"}: + return False, ( + f"Subject prefix '{subject_prefix}' does not match files changed.\n" + f"config_format commits must not include other components." + ) + # ------------------------------------------------ # Multiple-component detection # ------------------------------------------------ diff --git a/.github/scripts/tests/test_commit_lint.py b/.github/scripts/tests/test_commit_lint.py index ec6b9982a03..0496e3ed641 100644 --- a/.github/scripts/tests/test_commit_lint.py +++ b/.github/scripts/tests/test_commit_lint.py @@ -622,6 +622,75 @@ def test_valid_config_file_changes(): ok, _ = validate_commit(commit) assert ok is True +# ----------------------------------------------------------- +# config_format strict rules +# ----------------------------------------------------------- + +def test_valid_config_format_commit(): + """ + When files under src/config_format are modified, the subject MUST use + the umbrella prefix 'config_format:'. + + This ensures config_format is treated as a logical subsystem rather than + exposing internal implementation names (cf_yaml, cf_fluentbit, etc.) + in commit subjects. + """ + commit = make_commit( + "config_format: cf_yaml: fix include resolution\n\nSigned-off-by: User", + ["src/config_format/flb_cf_yaml.c"] + ) + ok, _ = validate_commit(commit) + assert ok is True + + +def test_error_cf_yaml_prefix_not_allowed(): + """ + Internal implementation prefixes like 'cf_yaml:' must NOT be allowed + as commit subjects when modifying src/config_format. + + The umbrella prefix 'config_format:' must be used instead. + """ + commit = make_commit( + "cf_yaml: fix include resolution\n\nSigned-off-by: User", + ["src/config_format/flb_cf_yaml.c"] + ) + ok, msg = validate_commit(commit) + assert ok is False + assert "config_format:" in msg + + +def test_error_yaml_prefix_not_allowed(): + """ + Generic implementation prefixes like 'yaml:' must NOT be allowed + for src/config_format changes. + + This prevents leaking format-specific implementation details into + commit history. + """ + commit = make_commit( + "yaml: fix include resolution\n\nSigned-off-by: User", + ["src/config_format/flb_cf_yaml.c"] + ) + ok, msg = validate_commit(commit) + assert ok is False + assert "config_format:" in msg + + +def test_valid_config_format_multiple_files(): + """ + Modifying multiple files under src/config_format should still require + the 'config_format:' umbrella prefix. + """ + commit = make_commit( + "config_format: refactor include handling\n\nSigned-off-by: User", + [ + "src/config_format/flb_cf_yaml.c", + "src/config_format/flb_cf_fluentbit.c", + ] + ) + ok, _ = validate_commit(commit) + assert ok is True + # ----------------------------------------------------------- # Additional Tests: validate_commit Complex Scenarios