From 840c4a60c040af5c6a8aca6dddd08b16a9beebf4 Mon Sep 17 00:00:00 2001 From: Ole Herman Schumacher Elgesem Date: Thu, 9 Apr 2026 00:20:39 +0200 Subject: [PATCH 1/2] cfengine format: Adjusted tests to single line more promises Signed-off-by: Ole Herman Schumacher Elgesem --- .../007_class_guarded_empty_lines.expected.cf | 6 ++--- tests/format/009_single_line.expected.cf | 13 ++++++++++ tests/format/009_single_line.input.cf | 26 +++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 tests/format/009_single_line.expected.cf create mode 100644 tests/format/009_single_line.input.cf diff --git a/tests/format/007_class_guarded_empty_lines.expected.cf b/tests/format/007_class_guarded_empty_lines.expected.cf index d340c89..015b283 100644 --- a/tests/format/007_class_guarded_empty_lines.expected.cf +++ b/tests/format/007_class_guarded_empty_lines.expected.cf @@ -2,10 +2,8 @@ bundle agent main { vars: hpux:: - "package_dir" - string => "$(sys.flavour)_$(sys.arch)"; + "package_dir" string => "$(sys.flavour)_$(sys.arch)"; !hpux:: - "package_dir" - string => "$(sys.class)_$(sys.arch)"; + "package_dir" string => "$(sys.class)_$(sys.arch)"; } diff --git a/tests/format/009_single_line.expected.cf b/tests/format/009_single_line.expected.cf new file mode 100644 index 0000000..84edad2 --- /dev/null +++ b/tests/format/009_single_line.expected.cf @@ -0,0 +1,13 @@ +bundle agent main +{ + packages: + "libyaml-dev" package_policy => "delete"; + "libxml2-dev" package_policy => "delete"; + "librsync-dev" package_policy => "delete"; + + debian.!bootstrap_pr_host:: + "libattr1-dev" package_policy => "delete"; + "libssl-dev" package_policy => "delete"; + "libpcre2-dev" package_policy => "delete"; + "libacl1-dev" package_policy => "delete"; +} diff --git a/tests/format/009_single_line.input.cf b/tests/format/009_single_line.input.cf new file mode 100644 index 0000000..9f1efe4 --- /dev/null +++ b/tests/format/009_single_line.input.cf @@ -0,0 +1,26 @@ +bundle agent main +{ + packages: + "libyaml-dev" + package_policy => "delete"; + + "libxml2-dev" + package_policy => "delete"; + + "librsync-dev" + package_policy => "delete"; + + debian.!bootstrap_pr_host:: + "libattr1-dev" + package_policy => "delete"; + + "libssl-dev" + package_policy => "delete"; + + "libpcre2-dev" + package_policy => "delete"; + + "libacl1-dev" + package_policy => "delete"; + +} From 64e5b8e76c5a072e4d528d3f95c8f73daa246708 Mon Sep 17 00:00:00 2001 From: Ole Herman Schumacher Elgesem Date: Thu, 9 Apr 2026 00:21:28 +0200 Subject: [PATCH 2/2] cfengine format: Single line promises in more cases Co-authored-by: Claude Opus 4.6 (1M context) Signed-off-by: Ole Herman Schumacher Elgesem --- src/cfengine_cli/format.py | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/cfengine_cli/format.py b/src/cfengine_cli/format.py index d89735d..c48a874 100644 --- a/src/cfengine_cli/format.py +++ b/src/cfengine_cli/format.py @@ -207,6 +207,25 @@ def stringify(node, indent, line_length): return [single_line] +def can_single_line_promise(node, indent, line_length): + """Check if a promise node can be formatted on a single line.""" + if node.type != "promise": + return False + children = node.children + attr_children = [c for c in children if c.type == "attribute"] + next_sib = node.next_named_sibling + has_continuation = next_sib and next_sib.type == "half_promise" + if len(attr_children) != 1 or has_continuation: + return False + promiser_node = next((c for c in children if c.type == "promiser"), None) + if not promiser_node: + return False + line = ( + text(promiser_node) + " " + stringify_single_line_node(attr_children[0]) + ";" + ) + return indent + len(line) <= line_length + + def autoformat(node, fmt, line_length, macro_indent, indent=0): previous = fmt.update_previous(node) if previous and previous.type == "macro" and text(previous).startswith("@else"): @@ -273,13 +292,7 @@ def autoformat(node, fmt, line_length, macro_indent, indent=0): attr_children = [c for c in children if c.type == "attribute"] next_sib = node.next_named_sibling has_continuation = next_sib and next_sib.type == "half_promise" - parent = node.parent - in_class_guard = parent and parent.type in [ - "class_guarded_promises", - "class_guarded_body_attributes", - "class_guarded_promise_block_attributes", - ] - if len(attr_children) == 1 and not has_continuation and not in_class_guard: + if len(attr_children) == 1 and not has_continuation: promiser_node = next((c for c in children if c.type == "promiser"), None) if promiser_node: line = ( @@ -302,7 +315,15 @@ def autoformat(node, fmt, line_length, macro_indent, indent=0): elif child.type == "promise": prev = child.prev_named_sibling if prev and prev.type in ["promise", "half_promise"]: - fmt.print("", 0) + # Skip blank line between consecutive single-line promises + promise_indent = indent + 2 + both_single = ( + prev.type == "promise" + and can_single_line_promise(prev, promise_indent, line_length) + and can_single_line_promise(child, promise_indent, line_length) + ) + if not both_single: + fmt.print("", 0) elif child.type in [ "class_guarded_promises", "class_guarded_body_attributes",